经常会有一些朋友问 go 语言的一些问题和疑惑, 其实好多问题在官方文档和 stackoverflow 里都有详细的讲解, 只要你肯花时间读一遍官方文档 https://golang.org/ref/spec 和 Effective Go https://golang.org/doc/effective_go.html 基本上都有找到答案. 本文总结一下大家经常问到的一些问题, 长期更新.
代码都在 github 上, 地址 https://github.com/lpxxn/gocommonquestions
new 和 make 的区别
简单来说, new(T) 用于分配内存, 返回指向 T 类型的一个指针, 指针的值为 T 类型的零值
- n1 := new(int)
- fmt.Println(n1) // console the address of n1
- fmt.Println(*n1 == 0) // zero value
- type T struct {
- I int
- A string
- Next *T
- }
- n2 := new(T)
- fmt.Println(n2)
- fmt.Println(n2.I == 0)
- fmt.Println(n2.Next == nil)
- fmt.Println(n2.A == "")
- n3 := new([]int)
- fmt.Println(n3)
- fmt.Println(*n3 == nil)
make(T) 只能用于 slice,map 和 channel, 返回非零值的 T.
- m1 := make([]int, 1)
- fmt.Println(m1)
- m2 := make(map[int]string)
- m2[0] = "abcde"
- m3 := make(chan int)
- m4 := make(chan int, 5)
make 返回的是类型本身, new 返回的是指向类型的指针
相关讲解
- https://stackoverflow.com/questions/9320862/why-would-i-make-or-new
- https://golang.org/doc/effective_go.html#allocation_new
- https://golang.org/ref/spec#The_zero_value
是否需要主动关闭 channel
除非你的程序需要等待 channel 关闭后做一些操作, 不用主动去关闭 channel. 当没有地方在使用这个 channel 的时候 go 的垃圾回收系统会自动回收, 如果 channel 里还有值, 但是没有地方引用了, 也会被回收.
下面的小例子就是在等待 channel c1 和 c2 关闭后, 再做一些事情.
- func main() {
- c1 := make(chan int, 3)
- go test1(c1)
- for v := range c1 {
- fmt.Println(v)
- }
- fmt.Println("after close c1 do something")
- c2 := make(chan bool)
- go func() {
- time.AfterFunc(time.Second * 3, func() {
- close(c2)
- })
- }()
- _, close := <- c2
- if !close {
- fmt.Println("after c2 closed do something")
- }
- fmt.Println("end")
- }
- func test1(c chan<- int) {
- for i := 0; i < 5; i++ {
- c <- i
- }
- close(c)
- }
相关讲解: https://stackoverflow.com/questions/8593645/is-it-ok-to-leave-a-channel-open
- https://groups.google.com/forum/#!msg/golang-nuts/pZwdYRGxCIk/qpbHxRRPJdUJ https://groups.google.com/forum/#!msg/golang-nuts/pZwdYRGxCIk/qpbHxRRPJdUJ
- https://groups.google.com/forum/#!topic/golang-nuts/KtIyc5lTRJY
Unbuffered channel 和 buffered channel 区别
- buffered channel
- c3 := make(chan bool, 5) // buffered channel
buffered channel 可以持续的发送数据到 channel, 直到 channel 满为至. 不用等待是否有接收 channel.
如果 channel 满了, 会等待读取 channel, 当有 channel 被读取, 就会继续发送数据到 channel
- c3 := make(chan bool, 5) // buffered channel
- go func() {
- for i := 0; i < 20; i++ {
- c3 <- i % 2 == 0
- }
- close(c3)
- }()
- for v := range c3 {
- fmt.Println(v)
- }
- unbuffered channel
下面这两种声明是一样的
- c1 := make(chan bool, 0) // unbuffered channel
- c2 := make(chan bool) // unbuffered channel
unbuffered channel 的接收 channel 会一直阻塞, 直到有值传给 channel, 也可以说发送 channel 会一直阻塞, 至到有接收 channel
- c1 := make(chan bool, 0) // unbuffered channel
- c2 := make(chan bool) // unbuffered channel
- go func() {
- c1 <- false
- time.Sleep(time.Second * 2)
- c2 <- true
- }()
- fmt.Println(<-c1)
- fmt.Println(<-c2)
相关讲解:
- https://stackoverflow.com/questions/23233381/whats-the-difference-between-c-makechan-int-and-c-makechan-int-1
- https://golang.org/doc/effective_go.html
定义类型和组合类型的区别
定义类型, 也可以说是别名和组合类型的区别
有一个 Test 的结构, NewTest 是以 Test 为类型的一个定义, New2Test 和 New3Test 都是组合类型
- type Test struct { N int }
- func (m *Test) Name() { fmt.Println("abc")}
- // NewTest does not inherit any functions of Test
- // can access fields
- type NewTest Test
- // New2Test is composite type, it inherit all functions of Test
- // can access fields
- type New2Test struct {
- Test
- }
- // if embedded type is pointer you must initialized it
- type New3Test struct {
- *Test
- }
1. 定义类型 NewTest 相当于一个新的类型, 他不能直接调用 Test 的方法, 但是可以访问 Test 的字段. 如果想调用原类型的方法需要做转换
2.New2Test 和 New3Test 都是组合类型, 他俩都可以直接调用 Test 的方法和访问 Test 的字段, 他俩的不同之处就是一个是值组合一个是指针组合
3. 在实例化 New3Test 的时候需要手动实例化 * Test 指针
- n := NewTest{}
- n.N = 1
- // n have no method
- // n.Name() // error
- v := (*Test)(&n)
- v.Name()
- v2 := Test(n)
- v2.Name()
- n2 := New2Test{}
- n2.N = 2
- n2.Name()
- n3 := New3Test{Test: new(Test)}
- // access filed N will panic if you do not initialized *Test
- n3.N = 3
- n3.Name()
相关的解答:
- https://stackoverflow.com/questions/28800672/how-to-add-new-methods-to-an-existing-type-in-go/28800807#28800807
- https://golang.org/ref/spec#Type_declarations
- ---
来源: https://www.cnblogs.com/li-peng/p/8990701.html