golang语法要点笔记
golang学习笔记
读《go学习笔记第四版》 《学习go语言》 《gopl-zh》《Go语言实战》记录
多变量赋值时,先计算所有相关值,然后再从左到右依次赋值。
data, i := []int{, , },
i, data[i] = ,
fmt.Println(i) //
fmt.Println(data) //[6 2 3]
用{}区分代码块
常量值必须是编译期可确定的数字、字符串、布尔值。 未使用局部常量不会引发编译错误。
const (
_ = iota // iota = 0
KB int64 = << ( * iota) // iota = 1
MB // 与 KB 表达式相同,但 iota = 2
GB
TB
)
const (
a = iota
b = iota
c = iota
)
可以简写
const (
a = iota
b
c
)
const (
a = iota //
b //
c //
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //
)
fmt.Println(a,b,c,d,e,f,g,h,i)
// 0 1 2 ha ha 100 100 7 8
const (
i=<<iota
j=<<iota
k
l
) func main() {
fmt.Println("i=",i)
fmt.Println("j=",j)
fmt.Println("k=",k)
fmt.Println("l=",l)
}
//output:
i=
j=
k=
l=
var s []int // len(s) == 0, s == nil
s = nil // len(s) == 0, s == nil
s = []int(nil) // len(s) == 0, s == nil
s = []int{} // len(s) == 0, s != nil
map中的元素并不是一个变量,不能对map的元素进行取址操作
range 会复制对象
a := []int{, , }
for i, v := range a { // index、value 都是从复制品中取出。
if i == { // 在修改前,我们先修改原数组。
a[], a[] = ,
fmt.Println(a) // 确认修改有效,输出 [0, 999, 999]。
}
a[i] = v + // 使⽤用复制品中取出的 value 修改原数组。
}
fmt.Println(a) // 输出 [100, 101, 102]。
s := []int{, , , , }
for i := range s { // 复制 struct slice { pointer, len, cap }。
if i == {
s = s[:] // 对 slice 的修改,不会影响 range。
s[] = // 对底层数据的修改。
}
}
fmt.Println(s) //[1 2 100 4 5]
//range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。
for i, c := range "go" {
fmt.Println(i, c)
}
var employeeOfTheMonth *Employee = &dilbert
employeeOfTheMonth.Position += " (proactive team player)"
相当于
(*employeeOfTheMonth).Position += " (proactive team player)"
var c = [...]int {1, 2, 3, 4, 5} //由初始化列表决定数组长度,不可省去标识符 "...",否则将变成切片Slice
x := []int{, , }
i :=
switch i {
case x[]:
println("a")
case , : //同时匹配1,3
println("b")
default:
println("c")
}
switch i := x[]; { // 带初始化语句
case i > :
println("a")
case i < :
println("b")
default:
println("c")
}
MAP
/* map插入key - value对,各个国家对应的首都 */
countryCapitalMap [ "France" ] = "Paris"
countryCapitalMap [ "Italy" ] = "罗马"
countryCapitalMap [ "Japan" ] = "东京"
countryCapitalMap [ "India " ] = "新德里" /*使用键输出地图值 */ for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap [country])
} /*查看元素在集合中是否存在 */
captial, ok := countryCapitalMap [ "美国" ] /*如果确定是真实的,则存在,否则不存在 */
/*fmt.Println(captial) */
/*fmt.Println(ok) */
if (ok) {
fmt.Println("美国的首都是", captial)
} else {
fmt.Println("美国的首都不存在")
}
break 可用于 for、switch、select,而 continue 仅能用于 for 循环。
type User struct {
id int
name string
} func (self *User) Test() {
fmt.Printf("%p, %v\n", self, self)
}
func main() {
u := User{, "Tom"}
u.Test()
mValue := u.Test
mValue() // 隐式传递 receiver
mExpression := (*User).Test
mExpression(&u) // 显式传递 receiver
}
/*
0x210230000, &{1 Tom}
0x210230000, &{1 Tom}
0x210230000, &{1 Tom}
*/
type User struct {
id int
name string
} func (self User) Test() {
fmt.Println(self)
}
func main() {
u := User{, "Tom"}
mValue := u.Test // ⽴立即复制 receiver,因为不是指针类型,不受后续修改影响。
u.id, u.name = , "Jack"
u.Test()
mValue()
}
/*
{2 Jack}
{1 Tom}
*/
func (self *User) TestPointer() {
fmt.Printf("TestPointer: %p, %v\n", self, self)
}
func (self User) TestValue() {
fmt.Printf("TestValue: %p, %v\n", &self, self)
}
func main() {
u := User{, "Tom"}
fmt.Printf("User: %p, %v\n", &u, u)
mv := User.TestValue
mv(u)
mp := (*User).TestPointer
mp(&u)
mp2 := (*User).TestValue // *User ⽅方法集包含 TestValue。
mp2(&u) // 签名变为 func TestValue(self *User)。
} // 实际依然是 receiver value copy
/*
User : 0x210231000, {1 Tom}
TestValue : 0x210231060, {1 Tom}
TestPointer: 0x210231000, &{1 Tom}
TestValue : 0x2102310c0, {1 Tom}
*/
type Data struct{} func (Data) TestValue() {}
func (*Data) TestPointer() {}
func main() {
var p *Data = nil
p.TestPointer()
(*Data)(nil).TestPointer() // method value
(*Data).TestPointer(nil) // method expression
//p.TestValue() // invalid memory address or nil pointer dereference
// (Data)(nil).TestValue() // cannot convert nil to type Data
// Data.TestValue(nil) // cannot use nil as type Data in function argument
}
简短变量声明左边的变量可能并不是全部都是刚刚声明的。如 果有一些已经在相同的词法域声明过了,那么简短变量声明语句对这些已经声明过 的变量就只有赋值行为了,简短变量声明语句中必须至少要声明一个新的变量。如果变量 是在外部词法域声明的,那么简短变量声明语句将会在当前词法域重新声明一个新的变量
//交换两个元素
x, y = y, x
a[i], a[j] = a[j], a[i]
//获得整数对应二进制数1的个数
var pc []byte func init() {
for i := range pc {
pc[i] = pc[i/] + byte(i&)
}
fmt.Printf("%b", pc)
} func PopCount(x uint64) int {
return int(pc[byte(x>>(*))] +
pc[byte(x>>(*))] +
pc[byte(x>>(*))] +
pc[byte(x>>(*))] +
pc[byte(x>>(*))] +
pc[byte(x>>(*))] +
pc[byte(x>>(*))] +
pc[byte(x>>(*))])
}
表达式 x&(x-1) 用于将x的最低的一个非零的bit位清零。可已用来计算二进制数1的个数
作用域
if x := f(); x == {
fmt.Println(x)
} else if y := g(x); x == y {
fmt.Println(x, y)
} else {
fmt.Println(x, y)
}
fmt.Println(x, y) // compile error: x and y are not visible here
var cwd string
func init() {
cwd, err := os.Getwd() // compile error: unused: cwd
if err != nil {
log.Fatalf("os.Getwd failed: %v", err)
}
}
虽然cwd在外部已经声明过,但是 := 语句还是将cwd和err重新声明为新的局部变量。因为内 部声明的cwd将屏蔽外部的声明,因此上面的代码并不会正确更新包级声明的cwd变量。
最直接的方法是通过单独声明err变量,来避免使 用 := 的简短声明方式:
var cwd string
func init() {
var err error
cwd, err = os.Getwd()
if err != nil {
log.Fatalf("os.Getwd failed: %v", err)
}
}
运算符号:
在Go语言中,%取模运算 符的符号和被取模数的符号总是一致的,因此 -5%3 和 -5%-3 结果都是-2。除法运算符 / 的 行为则依赖于操作数是否为全为整数,比如 5.0/4.0 的结果是1.25,但是5/4的结果是1,因为 整数除法会向着0方向截断余数。
位运算:
^ 位运算 XOR //只有一个1时返回1
&^ 位清空 (AND NOT)
位操作运算符 ^ 作为二元运算符时是按位异或(XOR),当用作一元运算符时表示按位取反
结构
点操作符也可以和指向结构体的指针一起工作:
var employeeOfTheMonth *Employee = &dilbert
employeeOfTheMonth.Position += " (proactive team player)"
相当于
(*employeeOfTheMonth).Position += " (proactive team player)"
dilbert.Position = "hello" 相当于 (&dilbert).Position = "hello2"
pp := &Point{, }
相当于
pp := new(Point)
*pp = Point{, }
w = Wheel{Circle{Point{, }, }, }
等价于
w = Wheel{
Circle: Circle{
Point: Point{X: , Y: },
Radius: ,
},
Spokes: , //NOTE: trailing comma necessary here (and at Radius)
}
// squares返回一个匿名函数。
// 该匿名函数每次被调用时都会返回下一个数的平方。
func squares() func() int {
var x int
return func() int {
x++
return x * x
}
}
func main() {
f := squares()
fmt.Println(f()) // "1"
fmt.Println(f()) // "4"
fmt.Println(f()) // "9"
fmt.Println(f()) // "16"
}
结构
var (
mu sync.Mutex // guards mapping
mapping = make(map[string]string)
) func Lookup(key string) string {
mu.Lock()
v := mapping[key]
mu.Unlock()
return v
}
下面这个版本在功能上是一致的,但将两个包级别的变量放在了cache这个struct一组内:
var cache = struct {
sync.Mutex
mapping map[string]string
}{
mapping: make(map[string]string),
} func Lookup(key string) string {
cache.Lock()
v := cache.mapping[key]
cache.Unlock()
return v
}
type Point struct{ X, Y float64 } func (p Point) Add(q Point) Point { return Point{p.X + q.X, p.Y + q.Y} }
func (p Point) Sub(q Point) Point { return Point{p.X - q.X, p.Y - q.Y} } type Path []Point func (path Path) TranslateBy(offset Point, add bool) {
var op func(p, q Point) Point
if add {
op = Point.Add
} else {
op = Point.Sub
}
for i := range path {
// Call either path[i].Add(offset) or path[i].Sub(offset).
path[i] = op(path[i], offset)
}
}
deferred
func ma() {
fmt.Println("im ma")
} func main() {
defer ma()
fmt.Println("start")
}
/*
start
im ma
*/
func ma() func() {
fmt.Println("im ma")
return func() {
fmt.Print("ma func end")
}
} func main() {
defer ma()()
fmt.Println("start")
}
/*
im ma
start
ma func end
*/
接口
type IntSet struct { /* ... */ }
func (*IntSet) String() string
var _ = IntSet{}.String() // compile error: String requires *IntSet receiver 但是我们可以在一个IntSet值上调用这个方法: var s IntSet
var _ = s.String() // OK: s is a variable and &s has a String method 然而,由于只有*IntSet类型有String方法,所以也只有*IntSet类型实现了fmt.Stringer接口: var _ fmt.Stringer = &s // OK
var _ fmt.Stringer = s // compile error: IntSet lacks String method
array := [5]*int{0: new(int), 1: new(int)}
*array[0] = 10
*array[1] = 20
创建一个包含 100 万个 int 类型元素的数组
var array [1e6]int
nil slice 和 empty slice 区别 https://blog.csdn.net/bobodem/article/details/80658466
nil slice
var slice []int
empty slice
slice := make([]int,0)//或者
slice := []int{}
根据内存和性能来看,在函数间传递数组是一个开销很大的操作。在函数之间传递变量时,
总是以值的方式传递的。如果这个变量是一个数组,意味着整个数组,不管有多长,都会完整复
制,并传递给函数。
在函数间传递切片就是要在函数间以值的方式传递切片。由于切片的尺寸很小,在函数间复
制和传递切片成本也很低。由于与切片关联的数据包含在底层数组里,不属于切片本身,所以将切片
复制到任意函数的时候,对底层数组大小都不会有影响。复制时只会复制切片本身,不会涉及底
层数组。
在函数间传递映射并不会制造出该映射的一个副本。实际上,当传递映射给一个函数,并对
这个映射做了修改时,所有对这个映射的引用都会察觉到这个修改。这个特性和切片类似,保证可以用很小的成本来复制映射。
func main() {
slice := []int{, , , , }
newSliceA := slice[::]
newSliceB := slice[:]
newSliceA = append(newSliceA, )
fmt.Println(slice)
fmt.Println(newSliceA)
newSliceB = append(newSliceB, )
fmt.Println(slice)
fmt.Println(newSliceA)
}
/*
[10 20 30 40 50]
[20 30 22]
[10 20 30 22 50]
[20 30 22]
*/
func main() {
slice := make([]int ,1E6)
fmt.Println(len(slice))
fmt.Println(cap(slice))
slice = append(slice, )
fmt.Println(len(slice))
fmt.Println(cap(slice))
/**
1000000
1000000
1000001
1250304
*/
}
Go 语言里的引用类型有如下几个:切片、映射、通道、接口和函数类型
break
//利用 break 可以提前退出循环,break 终止当前的循环。
fo r i := ; i < ; i++ {
i f i > {
break ← 终止这个循环,只打印 到 }
println(i)
} 循环嵌套循环时,可以在 break 后指定标签。用标签决定哪个循环被终止: J: for j := ; j < ; j++ {
for i := ; i < ; i++ {
if i > {
break J ← 现在终止的是 j 循环,而不是 i 的那个
}
println(i)
}
}
Switch
//Go 的 switch 非常灵活。表达式不必是常量或整数,执行的过程从上至//下,直到找到匹
//配项,而如果 switch 没有表达式,它会匹配 true 。这产生一种可能——//使用 switch
//编写 if-else-if-else 判断序列。
func unhex(c byte) byte {
switch {
case '' <= c && c <= '':
return c - ''
case 'a' <= c && c <= 'f':
return c - 'a' +
case 'A' <= c && c <= 'F':
return c - 'A' +
}
return
}
//它不会匹配失败后自动向下尝试,但是可以使用 fallthrough 使其这样做。没有 fallthrough:
switch i {
case : // 空的 case 体
case :
f() // 当 i == 0 时,f 不会被调用!
}
而这样:
switch i {
case : fallthrough
case :
f() // 当 i == 0 时,f 会被调用!
}
//用 default 可以指定当其他所有分支都不匹配的时候的行为。
switch i {
case :
case :
f()
defaul t:
g() // 当 i 不等于 0 或 1 时调用
}
//分支可以使用逗号分隔的列表。
func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&', '=', '#', '+': ← , as ”or”
return true
}
return false
}
Slice
s1 := []int{, , }
s2 := s1
s1[] =
fmt.Println(s1, s2) //[1 4 3] [1 4 3] d := func (s1 []int) {
s1[] =
}
d(s1)
fmt.Println(s1, s2) //[1 4 5] [1 4 5]
闭包
func plusX(x int) func(int) int { .
return func(y int) int { retu rn x + y } .
}
. 再次定义一个函数返回一个函数;
. 在函数符号中使用局部变量 x。
defer
//在这个(匿名)函数中,可以访问任何命名返回参数:
//Listing 2.10. 在 defer 中访问返回值
func f() (ret i n t) { ← ret 初始化为零
defer func() {
ret++ ← ret 增加为 }()
return ← 返回的是 而不是 !
}
golang语法要点笔记的更多相关文章
- Golang 语法学习笔记
Golang 语法学习笔记 包.变量和函数. 包 每个 Go 程序都是由包组成的. 程序运行的入口是包 main. 包名与导入路径的最后一个目录一致."math/rand" 包由 ...
- golang语法笔记
开始微服务,那就先温习下golang语法吧; golang变量类型 1. 整形 Go %b 表示为二进制 %c 该值对应的unicode码值 %d 表示为十进制 %o 表示为八 ...
- Golang语法与代码格式速记【转】
// Description: Golang语法与代码格式速记 // Author: cxy // Date: 2013-04-01 // Version: 0.3 // TODO 说明 // TOD ...
- css3【语法要点】
语法要点 display: -webkit-box; /* 老版本语法: Safari, iOS, Android browser, older WebKit browsers. */ display ...
- JavaScript的语法要点 1 - Lexically Scoped Language
作为从一开始接触C.C++.C#的程序员而言,JavaScript的语法对我来说有些古怪,通过最近一年的接触,对它有了一定的了解,于是想把它的一些语法要点记录下来. 1. Block Scope vs ...
- golang语法学习(一):变量,常量以及数据类型
学习一门新的语言肯定是要从他的主要的语法開始,语法构成了整个程序设计的基础,从语法中我们也能够看到这门语言的一些特性.可是话说回来.语法这东西,不同的语言大同小异,所以这也对语法的记忆造成了一定的难度 ...
- MarkDown语法 学习笔记 效果源码对照
MarkDown基本语法学习笔记 Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式. 下面将对Markdown的基本使用做一个介绍 目 ...
- 毕业设计 之 五 PHP语法学习笔记
毕业设计 之 四 PHP语法学习笔记 作者:20135216 平台:windows10 软件:XAMPP,DreamWeaver 说明:该笔记是对网站编程语言的详细学习 一.PHP基础 0. 关于环境 ...
- Lua语法要点2
[Lua语法要点2] 1.Lua函数 function 可以添加 local 关键字.添加后为局部函数,不添加(默认)为全局函数.return 可以返回多个返回值,以, 分隔. 使用 ... 来表示变 ...
随机推荐
- 在浏览器里使用SAPGUI
事务码SICF,service name输入WEBGUI, 点右键,选择Test Service: 可以在浏览器里敲SE38进入ABAP editor了: 然么缺乏语法高亮显示: 如果想要浏览器里的语 ...
- xwork-conversion.properties 目前没有解决方案
它没法变成.xml 这意味着项目里就只能这样
- CRF条件随机场简介<转>
转自http://hi.baidu.com/hehehehello/item/3b0d1f8ba1c2e5c698255f89 CRF(Conditional Random Field) 条件随机场是 ...
- Ubuntu16.04+GTX1080配置TensorFlow并实现图像风格转换
1. TensorFlow TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,表达了高层次的机器学习计算,大幅简化了第一代系统,并且具备更好的灵活性和可延展性. Te ...
- python特殊字符转义符号表示
- 【启发式拆分】bzoj5200: [NWERC2017]Factor-Free Tree
和bzoj4059: [Cerc2012]Non-boring sequences非常相似 Description 一棵Factor-Free Tree是指一棵有根二叉树,每个点包含一个正整数权值,且 ...
- js替换函数用法
定义和用法 replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串. 语法 stringObject.replace(regexp/substr,replac ...
- VUE2.0声明周期钩子:不同阶段不同钩子的开启
- 8.Yii2.0框架控制器接收get.post数据
8.Yii2.0框架控制器接收get.post数据 一.get传参 <?php /** * Created by Haima. * Author:Haima * QQ:228654416 * D ...
- 【报错】invalid or unexpected token
结果发现是把英文的,写成了中文字符,系统没法识别.