-
变量的包作用域
在Golang中,同个package中的非局部变量,可以认为是package作用域,可在package中(可能有多个文件)直接访问。 -
包变量导出
包内变量可以导出(即其他包可通过import调用)的标志,是变量的首字母是否大写。
首字母大写的包作用域变量,可以导出。
这是Golang中比较不方便的一点:如果要更改一个变量的可导出性,就需要更改其变量名。 -
Nil Pointer问题
Golang 中,指针常常作为函数参数。当指针参数==nil时,IDE并不会提醒程序员。导致我们使用空指针调用方法时panic。
对这种情况,可以在函数中对指针进行空判断:
func (a *A) getName() string {
if a == nil {
return ""
}
return a.Name
}
- 值传递和地址传递
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}
- 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()
}
}
}
网友评论