• 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)
    }

    简单测试垃圾回收channel

    func createChan() chan int64{
        c := make(chan int64, 10000)
        c <- 1
        return c
    }
    
    
    func main() {
    
        RM()
        for i := 0; i < 10; i++ {
            c := createChan()
            c <- 2
            RM()
            runtime.GC()
        }
        RM()
    }
    
    func RM(){
        var m runtime.MemStats
        runtime.ReadMemStats(&m)
        fmt.Println(m.Alloc)
    }

      

    相关讲解: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

    ---

  • 相关阅读:
    spring学习之模拟spring(spring原理解析)-01.xml文件的解析
    存储过程学习
    对象的深浅拷贝
    JavaScript 面向对象编程思想(二)
    深层剖析JavaScript 一
    深入剖析 css
    Vuex 总结
    h5 微信授权
    LeetCode
    echarts-liquidfill
  • 原文地址:https://www.cnblogs.com/li-peng/p/8990701.html
Copyright © 2020-2023  润新知