美文网首页
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