go語言的變量聲明并賦值運算符(:=)
基本功能
聲明并且賦值一個變量,其好處是不需要寫var三個字母,另外不需要寫類型,go語言會自動根據(jù)賦值的內容確定類型(但是這一點我不覺得是優(yōu)點,因為就不知道變量的類型是什么了)。
格式:
var := value
使用限制
不能在函數(shù)外面使用,即不能用來聲明全局變量。
== 例子 1
$ cat main.c
package main
import "fmt"
func main() {
a := 100
fmt.Printf("&a=%p\n", &a);
}
$ go build && main
&a=0xc42000e260
聲明并賦值變量a
== 例子 2
$ cat main.c
package main
import "fmt"
func main() {
var a int = 100
fmt.Printf("&a=%p\n", &a);
a := 100
fmt.Printf("&a=%p\n", &a);
}
$ go build && main
# main
./main.go:8: no new variables on left side of :=
第8行聲明并賦值變量a失敗,因為變量a已經(jīng)在第6行聲明過了。
== 例子 3
$ cat main.c
package main
import "fmt"
var a int = 100
func main() {
fmt.Printf("&a=%p\n", &a);
a := 100
fmt.Printf("&a=%p\n", &a);
}
$ go build && main
&a=0x4f8018
&a=0xc42000e268
雖然在第5行有聲明了一個全局變量a,在第9行依然可以聲明并賦值變量a,此時的a和全部變量a不是一個變量,打出來的地址不相同。
== 例子 4
$ cat main.c
package main
import "fmt"
func main() {
a := 100
fmt.Printf("&a=%p\n", &a);
{
a := 100
fmt.Printf("&a=%p\n", &a);
}
}
$ go build && main
&a=0xc420058168
&a=0xc420058198
第6行聲明并賦值了一個函數(shù)變量a,在第9行聲明并賦值了一個塊變量a,他們是兩個不同的變量。
總結v:=value的用法
- go在當前名字域范圍內搜索變量v
- 如果已經(jīng)找到v那么報錯:no new variables on left side of :=
- 如果沒有找到,那么在當前名字域范圍內定義變量v
- go并不在當前名字域的外層來搜搜變量
- 如果是直接的引用或者賦值除外,e.g., v=value, or w=v
- 當前名字域包括函數(shù)域,或者塊域
多變量的聲明賦值
== 例子1
$ cat main.c
package main
import "fmt"
func foo() (int, int) {
return 100, 200
}
func main() {
a, b := foo()
fmt.Printf("&a=%p, &b=%p\n", &a, &b);
}
$ go build && main
&a=0xc420058168, &b=0xc420058190
同時聲明并賦值兩個變量。
== 例子 2
$ cat main.c
package main
import "fmt"
func foo() (int, int) {
return 100, 200
}
func main() {
var a int = 0;
fmt.Printf("&a=%p\n", &a);
a, b := foo()
fmt.Printf("&a=%p, &b=%p\n", &a, &b);
}
$ go build && main
&a=0xc42000e260
&a=0xc42000e260, &b=0xc42000e280
第10行已經(jīng)聲明了變量a,第12行就不在重新定義變量a,只定義了變量b;可以看到兩個a打印出來的是同一個。
== 例子 3
$ cat main.c
package main
import "fmt"
func foo() (int, int) {
return 100, 200
}
func main() {
var a int = 0;
var b int = 0;
fmt.Printf("&a=%p\n", &a);
a, b := foo()
fmt.Printf("&a=%p, &b=%p\n", &a, &b);
}
$ go build && main
# simple
./main.go:13: no new variables on left side of :=
第13行聲明的變量a和b在前面均已經(jīng)聲明過,沒有新的變量。
總結多聲明賦值v1,v2,v3,:=value1,value2,value3,操作的用法
- 對多變量的賦值至少有一個是新變量。
- 對新變量在當前名字域創(chuàng)建變量
- 對老變量則使用已經(jīng)存在的老變量,注意老變量也必須是在當前名字域內的老變量,不含外層變量。
package main
import "fmt"
func foo() (int, int) {
return 100, 200
}
var b int = 0;
func main() {
var a int = 0;
fmt.Printf("&a=%p, &b=%p\n", &a, &b);
a, b := foo()
fmt.Printf("&a=%p, &b=%p\n", &a, &b);
}
$ go build && main
&a=0xc42006a018, &b=0x516b98
&a=0xc42006a018, &b=0xc42006a048
第11行聲明了變量a,在第13行聲明變量a和b的時候,因為a在第11行已經(jīng)聲明過了,所以這里不再定義新的變量a,而變量b雖然在第9行聲明了全局變量,但是根據(jù)聲明并賦值運算符(:=)的規(guī)則,在此并不會檢測全局變量區(qū),而只在當前名字域(即函數(shù)main)范圍內查找b,結果是沒有定義,所以在此會定義一個新變量b,這個變量b和全局變量b不是同一個變量。
結論
- 聲明并賦值運算符(:=)左邊至少得有一個變量是沒有定義的。
- 左邊變量有沒有定義的標準是在當前名字域范圍內,即當前語句塊,或者當前函數(shù);而不管是否在外層名字域范圍內已經(jīng)定義。