golang 常见疑惑总结

  经常会有一些朋友问go语言的一些问题和疑惑,其实好多问题在官方文档和stackoverflow里都有详细的讲解,只要你肯花时间读一遍官方文档Effective Go基本上都有找到答案。本文总结一下大家经常问到的一些问题,长期更新。

  代码都在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/#!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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏GopherCoder

『Go 语言学习专栏』-- 第三期

1373
来自专栏行者常至

012.golang 接口interface

721
来自专栏LIN_ZONE

javascript对象序列化(对象与JSON字符串的互换)

前一段时间用到h5的本地存储---需要把某个js对象存储在浏览器的本地存储中,用到了javascript对象的序列化与反序列化

662
来自专栏landv

Golang 新手可能会踩的 50 个坑【转】

译文:https://github.com/wuYin/blog/blob/master/50-shades-of-golang-traps-gotchas-m...

1862
来自专栏nimomeng的自我进阶

《Objective-C基础教程》笔记

1.xcode中,oc的.m文件代表message,指的是Objective-C的一个主要特性。 2.NS前缀的来历要追溯到次公局包还被成为NextStep,...

722
来自专栏机器学习算法与Python学习

Python最简编码规范

1976
来自专栏小灰灰

SPI框架实现之旅二:整体设计

SPI框架实现之旅二:整体设计 上一篇简单的说了一下spi相关的东西, 接下来我们准备开动,本篇博文主要集中在一些术语,使用规范的约定和使用方式 设计思路 下...

2978
来自专栏C/C++基础

web前端开发初学者十问集锦(4)

利用JS来控制页面控件的显示和隐藏有两种方法,两种方法分别利用HTML的style中的两个属性,两种方法的不同之处在于控件隐藏后是否还在页面上占空位。

1562
来自专栏LIN_ZONE

javascript基础重点

1.在javascript中使用 == 比较,会自动转换数据类型再比较,有时候会 得到非常诡异的结果;一般情况下使用 === 比较,它不会自动转换数据类型,如果...

882
来自专栏北京马哥教育

Python最简编码规范

1937

扫码关注云+社区