Go語言學習筆記(二) 基本語法、變數、常量、型別
基本語法
Go語言中的標記
Go程式是由各種標記組成的,標記可以是關鍵字,識別符號,常量,字串文字或符號。例如,以下Go語句由六個標記組成:
fmt.Println("Hello, World!")
每個標記單獨表示為:
fmt
.
Println
(
"Hello, World!"
)
行分隔符
在Go程式中,行分隔符鍵是語句終止符。 也就是說,每個單獨的語句不需要特殊的分隔符如:;
,也不需要像在C編譯器放置;
作為語句終止符以指示一個邏輯實體的結束。
例如,以下是兩個不同的語句:
fmt.Println("Hello, World!" )
fmt.Println("I am in Go Programming World!")
註釋
註釋就類似在Go程式中幫助文字,並且它們被編譯器忽略。 它們以/*
開始,並以字元*/
結尾,如下所示:
/* my first program comments in Go */
不能在註釋中包含註釋,並且不能在字串或字元文字中出現。
識別符號
Go識別符號是用於標識變數,函式或任何其他使用者定義專案的名稱。識別符號以字母A
到Z
或a
到z
或下劃線_
開頭,後跟零個或多個字母,下劃線和數字(0
到9
)組成。
識別符號 = 字母 {字母 | unicode數字}。
Go不允許在識別符號中使用標點符號,例如@
$
和 %
。 Go是一種區分大小寫的程式語言。 因此,Manpower
和manpower
在Go中是兩個不同的識別符號。以下是一些可接受(合法)的識別符號示例:
mahesh kumar abc move_name a_123
myname50 _temp j a23b9 retVal
關鍵詞
以下列表顯示Go中的保留字。這些保留字不能用作常量或變數或任何其他識別符號名稱。
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 |
Go語言的空白行
只包含空格的行,或者可能帶有註釋,被稱為空行,Go編譯器完全忽略它。
空白行是用於描述空格,製表符,換行符和註釋的術語。 空格將語句的一部分與另一個語句隔開,並使編譯器能夠識別語句中的一個元素(例如int
)結束和下一個元素開始的位置。因此,在下面的語句中:
var age int;
在int
和age
之間必須至少有一個空格字元(通常是一個空格),以便編譯器能夠區分它們。 另一方面,如以下語句中:
fruit = apples + oranges; // get the total fruit
在 fruit
和=
之間,或在=
和apples
之間可不需要空格字元,但是如果想要增加可讀性,那麼可以隨意新增。
變數
Go語言的變數宣告方式與C和C++語言有明顯的不同。對於純粹的變數宣告,Go語言引入了關鍵字var,而型別資訊放在變數名之後,示例如下:
var v1 int
var v2 string
var v3 [10]int // 陣列
var v4 []int // 陣列切片
var v5 struct {
f int
}
var v6 *int // 指標
var v7 map[string]int // map,key為string型別,value為int型別
var v8 func(a int) int
var (
v1 int
v2 string
)
var v1 int = 10 // 正確的使用方式1
var v2 = 10 // 正確的使用方式2,編譯器可以自動推匯出v2的型別
v3 := 10 // 正確的使用方式3,編譯器可以自動推匯出v3的型別
指定型別已不再是必需的,Go編譯器可以從初始化表示式的右值推匯出該變數應該宣告為哪種型別,這讓Go語言看起來有點像動態型別語言,儘管Go語言實際上是不折不扣的強型別語言(靜態型別語言)。
出現在:=左側的變數不應該是已經被宣告過的,否則會導致編譯錯誤,比如下面這個寫法:
var i int
i := 2
會導致類似如下的編譯錯誤:
no new variables on left side of :=
多重賦值功能,比如下面這個交換i和j變數的語句:
i, j = j, i
多重返回和匿名變數:
func GetName() (firstName, lastName, nickName string) {
return "May", "Chan", "Chibi Maruko"
}
若只想獲得nickName,則函式呼叫語句可以用如下方式編寫:
_, _, nickName := GetName()
常量
Go語言的字面常量更接近我們自然語言中的常量概念,它是無型別的。只要這個常量在相應型別的值域範圍內,就可以作為該型別的常量,比如上面的常量-12,它可以賦值給int、uint、int32、int64、float32、float64、complex64、complex128等型別的變數。
-12
3.14159265358979323846 // 浮點型別的常量
3.2+12i // 複數型別的常量
true // 布林型別的常量
"foo" // 字串常量
通過const關鍵字,你可以給字面常量指定一個友好的名字:
const Pi float64 = 3.14159265358979323846
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", 無型別整型和字串常量
常量定義的右值也可以是一個在編譯期運算的常量表達式,比如
const mask = 1 << 3
由於常量的賦值是一個編譯期行為,所以右值不能出現任何需要執行期才能得出結果的表示式,比如試圖以如下方式定義常量就會導致編譯錯誤:
const Home = os.GetEnv("HOME")
原因很簡單,os.GetEnv()只有在執行期才能知道返回結果,在編譯期並不能確定,所以無法作為常量定義的右值。
Go語言預定義了這些常量:true、false和iota。iota比較特殊,可以被認為是一個可被編譯器修改的常量,在每一個const關鍵字出現時被重置為0,然後在下一個const出現之前,每出現一次iota,其所代表的數字會自動增1。
const ( // iota被重設為0
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
const (
a = 1 << iota // a == 1 (iota在每個const開頭被重設為0)
b = 1 << iota // b == 2
c = 1 << iota // c == 4
)
const (
u = iota * 42 // u == 0
v float64 = iota * 42 // v == 42.0
w = iota * 42 // w == 84
)
const x = iota // x == 0 (因為iota又被重設為0了)
const y = iota // y == 0 (同上)
const ( // iota被重設為0
c0 = iota // c0 == 0
c1 // c1 == 1
c2 // c2 == 2
)
const (
a = 1 <<iota // a == 1 (iota在每個const開頭被重設為0)
b // b == 2
c // c == 4
)
Go語言並不支援眾多其他語言明確支援的enum關鍵字。偽列舉:
const (
Sunday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays // 這個常量沒有匯出
)
型別
Go語言內建以下這些基礎型別:
- 布林型別:bool。
- 整型:int8、byte、int16、int、uint、uintptr等。
- 浮點型別:float32、float64。
- 複數型別:complex64、complex128。
- 字串:string。
- 字元型別:rune。
- 錯誤型別:error。
此外,Go語言也支援以下這些複合型別:
- 指標(pointer)
- 陣列(array)
- 切片(slice)
- 字典(map)
- 通道(chan)
- 結構體(struct)
- 介面(interface)
int和int32在Go語言裡被認為是兩種不同的型別,編譯器也不會幫你自動做型別轉換:
var value2 int32
value1 := 64 // value1將會被自動推導為int型別
value2 = value1 // 編譯錯誤
編譯錯誤類似於:
cannot use value1 (type int) as type int32 in assignment。
使用強制型別轉換可以解決這個編譯錯誤:
value2 = int32(value1) // 編譯通過
兩個不同型別的整型數不能直接比較,比如int8型別的數和int型別的數不能直接比較,但各種型別的整型變數都可以直接與字面常量(literal)進行比較,比如:
var i int32
var j int64
i, j = 1, 2
if i == j { // 編譯錯誤
fmt.Println("i and j are equal.")
}
if i == 1 || j == 2 { // 編譯通過
fmt.Println("i and j are equal.")
}
在Go語言中,字串也是一種基本型別。相比之下, C/C++語言中並不存在原生的字串型別,通常使用字元陣列來表示,並以字元指標來傳遞。
var str string // 宣告一個字串變數
str = "Hello world" // 字串賦值
ch := str[0] // 取字串的第一個字元
fmt.Printf("The length of \"%s\" is %d \n", str, len(str))
fmt.Printf("The first character of \"%s\" is %c.\n", str, ch)
輸出結果為:
The length of "Hello world" is 11
The first character of "Hello world" is H.
str := "Hello world" // 字串也支援宣告時進行初始化的做法
str[0] = 'X' // 編譯錯誤