go语言学习笔记
- if 可以有多个;隔开的语句,if xxx; yyy {…}。 golang语句分隔符其实是;但是可以省略
- golang 中函数名头大小写决定了函数在包外的可见性!
- a := value 简短变量声明只能用 在函数内, 注意是 声明
- go 中指针是不能改变的
- 编译器自动选择在栈上还是堆上分配空间,但是不由var还是new方式决定!
- 注意go 中 := 和 多重赋值, 和作用域的坑
- 包导入:. “xx”, _ “xx”, f “xx”
- 在循环中调用函数或者goroutine方法,一定要采用显示的变量调用,不要再闭包函数里面调用循环的参数.
1
2
3
4
5
6
7
8
9
10
11
12for i:=0; i<limit; i++ {
go func() { DoSomething(i) }() //错误的做法
go func(i int){ DoSomething(i) }(i)//正确的做法
}
//go run -race
var msg = "hello"
go func() {
fmt.Println(msg)
}
msg = "bye"
//bye - var f float64 = 212
fmt.Println((5 / 9) * (f - 32)) //0 !!!
fmt.Println((f - 32) * 5 / 9) //100
fmt.Println((f - 32) * (5 / 9)) //0 !!!
常量是在编译时确定的!! go 中常量还有无类型字面量,精度更高。
在声明中,无类型会转换成相应类型 - slice 包含了一个指向数组的指针,但并非严格引用类型,append操作可能返回不同的底层
- 而数组是值类型,a = […]{1,2,3}; b := a; a[1] = 42; a,b 不等
- map == nil 时存入会异常. 允许对值为 nil 的 slice 添加元素,但对值为 nil 的 map 添加元素则会造成运行时 panic
- 在go语言中所有函数参数是值拷贝传入
- switch 语句中的 case 代码块会默认带上 break,但可以使用
fallthrough
来强制执行下一个 case 代码块 - 组合是go中面向对象的核心
- go中函数栈是可变栈,递归深度没有限制?
- print, println 不像fmt.print那样可以打印结构体等复杂类型,并没有格式化功能?
- 闭包中引用的局部变量是地址,而不是某一时刻的值。注意这个陷阱,这在其它语言中也存在
- defer 语句是在函数返回后执行!所以可以在函数内观察到返回值。参数是在defer声明时候确定
- 可以在一个函数中执行多条defer语句,它们的执行顺序与声明顺序相反
- 即使发生panic, defer语句也会执行!
- recover 只在defer函数中有用
- 语言中最小的封装单元是package, 可见性是以包为单位的
- 接口有个坑: 包含nil值的接口不是一个nil接口 ,一个接口中包含一个动态类型(一个具体的类型)和一个动态值两部分组成,接口可以和nil比较,这个nil表示一个空接口(不包含任何值的接口)。但是包含nil的接口不是空接口: var i1 *bytes.Buffer 和 var i2 io.Writer 都是nil但是不等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20println("----------------------------------")
var i1 io.Writer
println(i1)
println(i1 == nil)
var i2 *bytes.Buffer
println(i2)
println(i2 == nil)
i1 = i2
println(i1)
//注意这里是false
println(i1 == nil)
----------------------------------
(0x0,0x0)
true
0x0
true
(0x53c260,0x0)
false - 接口赋值中,如果使用值,则所有实现的reciever都应是值类型,如果是指针,则没有这个限制,可以是值或者指针。
var a writer = ConcreteWriter{} vs var a *writer = &ConcreteWriter{} - 函数中可以安全的返回局部变量的地址。
- ch <-chan int: readonly channel, 只能读出; ch chan<- int: sendonly channel,只能写入