天天看點

golang的變量和常量,以及作用域

作者:寒笛過霜天

1 命名

Go 語言中的函數名, 變量名, 常量名, 類型名, 語句标号和包名等所有的命名, 都遵循一個簡單的命名規則:

一個名字必須以一個字母(Unicode 字母)或下劃線開頭, 後面可以跟任意數量的字母,數字或下劃線, 大寫字母和小寫字母是不同的: heapSort 和 Heapsort 是兩個不同的名字。

Go語言中類似 if 和 switch 的關鍵字有25個(均為小寫)。關鍵字不能用于自定義名字, 隻能在特定文法結構中使用。

break default func interface select

case defer go map struct

chan else goto package switch

const fallthrough if range type

continue for import return var

此外, 還有大約30多個預定義的名學, 比如int和true等, 主要對應内建的常量, 類型和函數。

内建常量:

true false iota nil

内建類型:

int int8 int16 int32 int64

uint uint8 uint16 uint32 uint64 uintptr

float32 float64 complex128 complex64

bool byte rune string error

内建函數:

make len cap new append copy close delete

complex real immag

panic recover

變量

變量是幾乎所有程式設計語言中最基本的組成元素, 變量是程式運作期間可以改變的量。

從根本上說, 變量相當于是對一塊資料存儲空間的命名, 程式可以通過定義一個變量來申請一塊資料存儲空間, 之後可以通過引用變量名名使用這塊存儲空間.

變量聲明

Go語言的變量聲明方式與C和C++語言有明顯的不同。對于純粹的變量聲明, Go語言引入了關鍵字var, 而類型資訊放在變量名之後, 示例如下:

var vl int

var v2 int

v3 := 10

var v4 int = 100

【執行個體】

package main

import "fmt"

var v1, v2 int

func main() {

fmt.Println("v1 = ", v1, "v2 =", v2) //v1 = 0 v2 = 0

}

//一次定義多個變量

var v3, v4 int

var(

v5 int

v6 int

)

注意: var v1, v2 int, string 此種定義方法是錯誤的!

變量初始化

對于聲明變量時需要進行初始化的場景, var關鍵字可以保留, 但不再是必要的元素, 如下所示:

var v1 int = 10 //方式1

var v2 = 10 //方式2,編譯器自動推導出v2的類型

v3 := 10 //方式3, 編譯器自動推導出v3的類型

fmt.Println("v3 type is ", reflect.TypeOf(v3)) //v3 type is int

//出現在 := 左側的變量不應該是已經被聲明過, :=

var v4 int

v4 := 2 //err

【執行個體】

package main

import (

"fmt"

"reflect"

"unsafe"

)

func main() { //左括号必須和函數名同行

v1 := 11.98 //方式3, 編譯器自動推導出v1的類型

var v2 int64 = 12

fmt.Println("v1 type is ", reflect.TypeOf(v1)) //檢視資料類型 結果: v1 type is int reflect: 反映, 顯示

fmt.Println(unsafe.Sizeof(v1)) //檢視占用記憶體空間大小 結果: 8

fmt.Println(int64(v1)) // 11 浮點數轉換為整數将去除小數位, 非四舍五入、

// fmt.Println(v2 > v1) // 不同的資料類型 會導緻文法錯誤 Error: invalid operation: v2 > v1 (mismatched types int64 and float64)

fmt.Println(float64(v2) > v1) // true 整數和浮點數比較大小時, 最好使将整數轉換為浮點數再比較大小;

}

變量指派

var vl int

v1 = 123

var v2, v3, v4 int

V2, v3, v4 = 1, 2, 3 //多重指派

i := 10

j := 20

i, j = j, i //多重指派

注意: 簡短聲明的變量隻能在函數内部定義

./one.go:6:1: syntax error: non-declaration statement outside function body

變量未使用問題

執行個體1:

package main

import "fmt"

var v1, v2 int

var (

v3 int

v4 string

)

func main() {

v3 := 100 //注意: 這裡能夠正常執行

v4 = "這是一個字元串"

if v3 == 100 && v4 != "" { // 這裡能正常運作, 變量v3和v4可以判斷已經使用

fmt.Println("兩個變量必須要使用")

}

v5 := 10

v5 = 100 //Error: a declared but not used

}

執行個體2:

package main

import "fmt"

var v1, v2 int

var (

v3 int

v4 string

)

func main() {

v1 = 10

v2 = 30

v3 := 100 //注意: 這裡能夠正常執行

v4 = "這是一個字元串"

fmt.Println("v1 = ", v1, "v2 =", v2)

if v2 == 40 {

fmt.Println("v3 = ", v3, "v4 =", v4) // if 語句下 v3 和 v4 變量也算已經使用, 盡管沒有最終執行

err := "這是第一個錯誤"

fmt.Println(err) //err 變量必須要使用 Error: err declared but not used

}

err := "這是第二個錯誤" // 這裡重複指派 不受 if 語句中 err := "這是一個錯誤" 影響

fmt.Println(err) //err 變量必須要使用 Error: err declared but not used

}

注意: 變量的使用的範圍包括 if 語句

【執行個體】

package main

import "fmt"

var v1, v2 int

var(

v3 int

v4 string

)

func main() {

v1 = 10

v2 = 30

v3 := 100 //注意: 這裡能夠正常執行

v4 = "這是一個字元串"

fmt.Println("v1 = ", v1, "v2 =",v2)

fmt.Println("v3 = ", v3, "v4 =",v4)

}

匿名變量

_(下劃線)是個特殊的變量名, 任何賦予它的值都會被丢棄:

_, i, _, j := 1, 2, 3, 4

func test()(int, string){

return 250, "sb"

}

_, str := test()

【執行個體】

package main

import(

"fmt"

)

func test()(int, string){

return 250, "sougou" //注意: 字元串型的隻能使用雙引号, 不能使用單引号

}

func main(){ //左括号必須和函數名同行

_, str := test()

fmt.Println("str = ", str)

}

多變量指派

在進行多變量指派操作時, 首先計算出所有右值, 然後再依次完成指派操作。

【執行個體】

package main

import(

"fmt"

)

func main(){

x, y := 1, 2

x, y = y + 3, x + 2

fmt.Println(x, y)

}

注意: 指派操作, 必須確定左右值類型相同。

常量

在Go語言中, 常量是指編譯期間就巴知且不可改變的值。常量可以是數值類型(包括整型, 浮點型和複數類型), 布爾類型, 字元串類型等。

字面常量(常量值)

所謂字面常量(literal), 是指程式中寫死的常量,如:

123

3.1415 //浮點類型的常量

3.2+12i //複數類型的常量

true //布爾類型的常量

"foo" //字元串常量

常量定義

const Pi float64 = 3.14

const zero = 0.0 //浮點常量, 自動推導類型

const ( //常量組

size int64 = 1024

eof = -1 //整型常量, 自動推導類型

)

const u, v float32 = 0, 3 //u = 0.0, v = 3.0 常量的多重指派

const a, b, c = 3, 4, "foo"

// a = 3, b = 4, c = "foo" //err, 常量不能修改

【執行個體】

package main

import (

"fmt"

)

func main() { //左括号必須和函數名同行

const (

x uint16 = 120

y // 與上一行 x 類型、右值相同

s = "abc"

z //與 s 類型、右值相同

)

fmt.Printf("%T, %v\n", y, y)

fmt.Printf("%T, %v", z, z)

/*

與變量不同的是, 常量 x 和 z 都沒有 used 的情況下,沒有出現緻命錯誤

uint16, 120

string, abc

*/

}

iota 枚舉

常量聲明可以使用iota常量生成器初始化, 它用于生成一組以相似規則初始化的常量, 但是不用每行都寫一遍初始化表達式。

在一個const 聲明語句中, 在第一個聲明的常量所在的行, iota将會被設定為0, 然後在每一個有常量聲明的行加一。

const(

x = iota //x == 0

y = iota //y == 1

z = iota //z == 2

w //這裡隐式地說w = iota, 是以w == 3。其實上面y和z可同樣不用"=iota"

)

const v = iota //每遇到一個const關鍵字, iota就會重置, 此時v == 0

const(

h, i, j = iota, iota, iota //h=0, i=0, j=0 iota在同一行值相同

)

const(

a = iota //a=0

b = "B"

c = iota //c=2

d, e, f = iota, iota, iota //d=3, e=3, f=3

g = iota //g = 4

)

const(

x1 = iota * 10 //x1 == 0

y1 = iota * 10 //yl == 10

z1 = iota * 10 //zl == 20

)

const(

a = iota // 0

b // 1

c = 100 // 100

d // 100 (與上一行常量右值表達式相同)

e = iota // 4 (恢複iota自增, 計數包括c、d)

f // 5

)

const (

a = iota //0 int (自增預設資料類型為int, 可顯式指定類型)

b float32 = iota //1 float32

c = iota //2 int (如不顯式指定iota, 則與b資料類型相同)

)

package main

import (

"fmt"

)

func main() {

const (

cpp = iota

_

python

golang

javascript

)

fmt.Println(cpp, javascript, python, golang) //0 4 2 3

}

變量作用域

作用域為已聲明辨別符所表示的常量、類型、變量、函數或包在源代碼中的作用範圍。

Go 語言中變量可以在三個地方聲明:

函數内定義的變量稱為局部變量

函數外定義的變量稱為全局變量

函數定義中的變量稱為形式參數

局部變量

在函數體内聲明的變量稱之為局部變量, 它們的作用域隻在函數體内, 參數和傳回值變量也是局部變量。

以下執行個體中 main() 函數使用了局部變量 a, b, c:

package main

import "fmt"

func main() {

/* 聲明局部變量 */

var a, b, c int

/* 初始化參數 */

a = 10

b = 20

c = a + b

fmt.Printf ("結果: a = %d, b = %d and c = %d\n", a, b, c)

}

以上執行個體執行輸出結果為:

結果: a = 10, b = 20 and c = 30

全局變量

在函數體外聲明的變量稱之為全局變量, 全局變量可以在整個包甚至外部包(被導出後)使用。

全局變量可以在任何函數中使用, 以下執行個體示範了如何使用全局變量:

package main

import "fmt"

/* 聲明全局變量 */

var g int

func main() {

/* 聲明局部變量 */

var a, b int

/* 初始化參數 */

a = 10

b = 20

g = a + b

fmt.Printf("結果: a = %d, b = %d and g = %d\n", a, b, g)

}

以上執行個體執行輸出結果為:

結果: a = 10, b = 20 and g = 30

Go 語言程式中全局變量與局部變量名稱可以相同, 但是函數内的局部變量會被優先考慮。執行個體如下:

package main

import "fmt"

/* 聲明全局變量 */

var g int = 20

func main() {

/* 聲明局部變量 */

var g int = 10

fmt.Printf("結果: g = %d\n", g)

}

以上執行個體執行輸出結果為:

結果: g = 10

形式參數

形式參數會作為函數的局部變量來使用。執行個體如下:

package main

import "fmt"

/* 聲明全局變量 */

var a int = 20;

func main() {

/* main 函數中聲明局部變量 */

var a int = 10

var b int = 20

var c int = 0

fmt.Printf("main()函數中 a = %d\n", a);

c = sum( a, b);

fmt.Printf("main()函數中 c = %d\n", c);

}

/* 函數定義-兩數相加 */

func sum(a, b int) int {

fmt.Printf("sum() 函數中 a = %d\n", a);

fmt.Printf("sum() 函數中 b = %d\n", b);

return a + b;

}

以上執行個體執行輸出結果為:

main()函數中 a = 10

sum() 函數中 a = 10

sum() 函數中 b = 20

main()函數中 c = 30

注意: 符号名字母大小寫決定了其作用域。 首字母大寫的為導出成員, 可被包外引用, 而小寫則僅能在包内使用。