美文网首页
Golang须知

Golang须知

作者: 平仄_pingze | 来源:发表于2018-10-10 17:25 被阅读5次
    1. 变量的包作用域
      在Golang中,同个package中的非局部变量,可以认为是package作用域,可在package中(可能有多个文件)直接访问。

    2. 包变量导出
      包内变量可以导出(即其他包可通过import调用)的标志,是变量的首字母是否大写。
      首字母大写的包作用域变量,可以导出。
      这是Golang中比较不方便的一点:如果要更改一个变量的可导出性,就需要更改其变量名。

    3. Nil Pointer问题
      Golang 中,指针常常作为函数参数。当指针参数==nil时,IDE并不会提醒程序员。导致我们使用空指针调用方法时panic。
      对这种情况,可以在函数中对指针进行空判断:

    func (a *A) getName() string {
        if a == nil {
            return ""
        }
        return a.Name
    }
    
    1. 值传递和地址传递
      Golang中所有函数参数传递都是值传递。
      无论是数字、字符串,还是slice、结构体,都会在传递值复制。
      如果希望进行引用传递,则可以传递变量的地址。
      示例:
    package main
    
    import "fmt"
    
    type A struct {
        val int64
    }
    
    func transValue(a A) {
        a.val = 2
    }
    
    func transAddress(a *A) {
        (*a).val = 2
    }
    
    func transAddress2(aP *A) {
        // 错误,这样a还是复制的
        a := *aP
        a.val = 3
    }
    
    func main() {
        a := A{val:1}
        transValue(a)
        fmt.Println(a)
        transAddress(&a)
        fmt.Println(a)
        transAddress2(&a)
        fmt.Println(a)
    }
    // 输出
    // {1}
    // {2}
    // {2}
    
    1. select和for结合,中止chan取值循环

    Basic sends and receives on channels are blocking. However, we can use select with a default clause to implement non-blocking sends, receives, and even non-blocking multi-way selects.
    If a value is available on messages then select will take the <-messages case with that value. If not it will immediately take the default case.

    func main() {
        stopChan := make(chan int)
        valsChan := make(chan int)
    
        go func () {
            time.Sleep(time.Duration(1e9))
            stopChan <- 1
        }()
    
        go func() {
            for i:=0; i<100; i++ {
                valsChan <- i
            }
        }()
    
        for {
            select {
                case <- stopChan:
                    return
                case val := <- valsChan:
                    time.Sleep(time.Duration(1e8))
                    fmt.Println(val)
            }
        }
    
        for val := range(valsChan) {
            time.Sleep(time.Duration(1e8))
            fmt.Println(val)
        }
    }
    

    执行后,发现无论像valsChan中传递多少值,都会在for循环执行到10次(或10次多一点)时中止循环。
    之所以可能多一点,是因为select是随机选择一个case执行,并不会优先执行<- stopChan

    如果希望准确的在第10次中断,则需要有优先级的select。select的优先级可以利用default实现,因为所有的case都优先于default。
    上面代码可修改如下:

        for {
            select {
                case <- stopChan:
                    return
                default:
                    val := <- valsChan
                    fmt.Println(val)
                    time.Sleep(time.Duration(1e8))
            }
        }
    

    但是,由于每次循环default总是执行,会导致deadlock。应该再用sync.WaitGroup帮助程序在valsChan全部取出后退出。如下:

    func main() {
    
        wg := sync.WaitGroup{}
    
        stopChan := make(chan int)
        valsChan := make(chan int)
    
        go func () {
            // 1s后停止
            time.Sleep(time.Duration(3e9))
            stopChan <- 1
        }()
    
        go func() {
            for i:=0; i<3; i++ {
                wg.Add(1)
                valsChan <- i
            }
    
            wg.Wait()
            stopChan <- 1
        }()
    
        for {
            select {
                case <- stopChan:
                    return
                case val := <- valsChan:
                //default:
                //  val := <- valsChan
                    fmt.Println("val", val)
                    time.Sleep(time.Duration(1e8))
                    wg.Done()
            }
        }
    
    }
    

    相关文章

      网友评论

          本文标题:Golang须知

          本文链接:https://www.haomeiwen.com/subject/ychmaftx.html