1.1 變量
Go 是靜態(tài)類型語?逐纬,不能在運(yùn)?期改變變量類型蛔屹。
使?關(guān)鍵字 var 定義變量,?動(dòng)初始化為零值豁生。如果提供初始化值兔毒,可省略變量類型,由編譯器?動(dòng)推斷甸箱。
var a int
var f float32 = 1.6
var s = "abc" ?//編譯器自動(dòng)推導(dǎo)類型
在函數(shù)內(nèi)部育叁,可?更簡略的 ":=" ?式定義變量,自動(dòng)推導(dǎo)類型摇肌。
func main() {
x := 66 ?// 注意檢查擂红,是定義新局部變量仪际,還是修改全局變量围小。該?式容易造成錯(cuò)誤。
//x:=22 ?//在一個(gè)main函數(shù)里定義過的類型树碱,不能再使用這種方式
}
可?次定義多個(gè)變量肯适。
var x, y, z int
var s, n = "abc", 123
var (
a int
b float32
)
func main() {
n, s := 0x1234, "Hello, World!"
println(x, s, n) ?//打印時(shí)自動(dòng)換行
}
多變量賦值時(shí),先計(jì)算所有相關(guān)值成榜,然后再從左到右依次賦值框舔。
data, i := [3]int{0, 1, 2}, 0
i, data[i] = 2, 100 // (i = 0) -> (i = 2), (data[0] = 100)
?_ ?實(shí)際上是一個(gè)只寫變量,你不能得到它的值,不能讀赎婚,?于忽略值刘绣,占位
func test() (int, string) {
return 1, "abc"
}
func main() {
_,s := test() ? //接受一個(gè)返回值挣输,忽略一個(gè)
println(s)
}
編譯器會(huì)將未使?的局部變量當(dāng)做錯(cuò)誤纬凤。
import(
"fmt" ?//導(dǎo)入一個(gè)輸入輸出的包,
_"fmt" ?//如果不使用撩嚼,可以前面加上 _ ?,不然編譯器會(huì)報(bào)錯(cuò)
)
var s string // 全局變量沒問題停士。
func main() {
i := 0 // Error: i declared and not used挖帘。 (可使? "_ = i" 規(guī)避)
}
注意重新賦值與定義新同名變量的區(qū)別。
s := "abc"
println(&s)
s, y := "hello", 20 // 重新賦值: 與前 s 在同?層次的代碼塊中恋技,且有新的變量被定義拇舀。
println(&s, y) // 通常函數(shù)多返回值 err 會(huì)被重復(fù)使?。
{
s, z := 1000, 30 // 定義新同名變量: 不在同?層次代碼塊蜻底。
println(&s, z)
}
輸出:
0x2210230f30
0x2210230f30 20
0x2210230f18 30
1.2 常量
常量值必須是編譯期可確定的數(shù)字骄崩、字符串、布爾值薄辅。
const x, y int = 1, 2 // 多常量初始化
const s = "Hello, World!" // 類型推斷
const ( // 常量組
a, b = 10, 100
c bool = false
)
func main() {
const x = "xxx" // 未使?局部常量不會(huì)引發(fā)編譯錯(cuò)誤刁赖。
}
不?持 1UL、 2LL 這樣的類型后綴长搀。
在常量組中宇弛,如不提供類型和初始化值,那么視作與上?常量相同源请。
const (
s = "abc"
x // x = "abc"
)
常量值還可以是 len枪芒、 cap、 unsafe.Sizeof 等編譯期可確定結(jié)果的函數(shù)返回值谁尸,
不能將函數(shù)的返回值賦給常量舅踪,因?yàn)楹瘮?shù)調(diào)用發(fā)生在運(yùn)行期
const (
a = "abc"
b = len(a)
c = unsafe.Sizeof(b)
)
如果常量類型?以存儲(chǔ)初始化值,那么不會(huì)引發(fā)溢出錯(cuò)誤良蛮。
const (
a byte = 100 // int to byte
b int = 1e20 // float64 to int, overflows
)
枚舉
關(guān)鍵字 iota 定義常量組中從 0 開始按?計(jì)數(shù)的?增枚舉值抽碌。
const (
Sunday = iota // 0
Monday // 1,通常省略后續(xù)?表達(dá)式决瞳。
Tuesday // 2
Wednesday // 3
Thursday // 4
Friday // 5
Saturday // 6
)
const (
_ = iota // iota = 0
KB int64 = 1 << (10 * iota) // iota = 1
MB // 與 KB 表達(dá)式相同货徙,但 iota = 2
GB
TB
)
在同?常量組中,可以提供多個(gè) iota皮胡,它們各?增?痴颊。
const (
A, B = iota, iota << 10 // 0, 0 << 10
C, D // 1, 1 << 10
)
如果 iota ?增被打斷,須顯式恢復(fù)屡贺。
const (
A = iota // 0
B // 1
C = "c" // c
D // c蠢棱,與上??相同。
E = iota // 4甩栈,顯式恢復(fù)泻仙。注意計(jì)數(shù)包含了 C、 D 兩?量没。
F // 5
)
package main
import "fmt"
func main() {
const (
? ? ?a = iota //0
? ? ?b //1
? ? ?c //2
? ? ?d = "ha" //獨(dú)?值玉转, iota += 1
? ? ?e //"ha" iota += 1?
? ? ?f = 100 //iota +=1
? ? ?g //100 iota +=1
? ? ?h = iota //7,恢復(fù)計(jì)數(shù)
? ? ?i //8
)
fmt.Println(a, b, c, d, e, f, g, h, i)
}
以上實(shí)例運(yùn)行結(jié)果為:
0 1 2 ha ha 100 100 7 8
1.3 基本類型
更明確的數(shù)字類型命名,?持 Unicode允蜈,?持常?數(shù)據(jù)結(jié)構(gòu)冤吨。序號(hào)類型和描述
1布爾型
布爾型的值只可以是常量 true 或者 false蒿柳。一個(gè)簡單的例子:var b bool = true。
2數(shù)字類型
整型 int 和浮點(diǎn)型 float32漩蟆、float64垒探,Go 語言支持整型和浮點(diǎn)型數(shù)字,并且原生支持復(fù)數(shù)怠李,其中位的運(yùn)算采用補(bǔ)碼圾叼。
3字符串類型:
字符串就是一串固定長度的字符連接起來的字符序列。Go的字符串是由單個(gè)字節(jié)連接起來的捺癞。Go語言的字符串的字節(jié)使用UTF-8編碼標(biāo)識(shí)Unicode文本夷蚊。
4派生類型:
包括:
(a) 指針類型(Pointer)
(b) 數(shù)組類型
(c) 結(jié)構(gòu)化類型(struct)
(d) Channel 類型
(e) 函數(shù)類型?
(f) 切片類型?
(g) 接口類型(interface)
(h) Map 類型
1.4 引?類型
引?類型包括 slice、 map 和 channel髓介。它們有復(fù)雜的內(nèi)部結(jié)構(gòu)惕鼓,除了申請(qǐng)內(nèi)存外,還需
要初始化相關(guān)屬性唐础。
內(nèi)置函數(shù) new 計(jì)算類型??箱歧,為其分配零值內(nèi)存,返回指針。? make 會(huì)被編譯器翻譯
成具體的創(chuàng)建函數(shù),由其分配內(nèi)存和初始化成員結(jié)構(gòu)牡属,返回對(duì)象??指針。
a := []int{0, 0, 0} // 提供初始化表達(dá)式损痰。
a[1] = 10
b := make([]int, 3) // slice.c: runtime·makeslice
b[1] = 10
c := new([]int)
c[1] = 10 // Error: invalid operation: c[1] (index of type *[]int)
1.5 類型轉(zhuǎn)換
不?持隱式類型轉(zhuǎn)換,即便是從窄向?qū)掁D(zhuǎn)換也不?。
var b byte = 100
// var n int = b // Error: cannot use b (type byte) as type int in assignment
var n int = int(b) // 顯式轉(zhuǎn)換
使?括號(hào)避免優(yōu)先級(jí)錯(cuò)誤。
*Point(p) // 相當(dāng)于 *(Point(p))
(*Point)(p)
<-chan int(c) // 相當(dāng)于 <-(chan int(c))
(<-chan int)(c)
同樣不能將其他類型當(dāng) bool 值使?蝉衣。
a := 100
if ? a { ? ?// Error: non-bool a (type int) used as if condition
? println("true")
}
1.6 字符串
字符串是不可變值類型,內(nèi)部?指針指向 UTF-8 字節(jié)數(shù)組仲智。
? 默認(rèn)值是空字符串 ""买乃。
? ?索引號(hào)訪問某字節(jié),如 s[i]钓辆。
? 不能?序號(hào)獲取字節(jié)元素指針。 &s[i] ?法肴焊。
? 不可變類型前联,?法修改字節(jié)數(shù)組。
? 字節(jié)數(shù)組尾部不包含 NULL娶眷。
使?索引號(hào)訪問字符 (byte)似嗤。
s := "abc"
println(s[0] == '\x61', s[1] == 'b', s[2] == 0x63)
輸出: ??true true true
使? "`" 定義不做轉(zhuǎn)義處理的原始字符串,?持跨?届宠。
s := `a
b\r\n\x00
c`
println(s)
輸出:
a
b\r\n\x00
c
連接跨?字符串時(shí)烁落, "+" 必須在上??末尾乘粒,否則導(dǎo)致編譯錯(cuò)誤。
s := "Hello, " + ? ?//必須加在上一行結(jié)尾
"World!"
s2 := "Hello, "
+ "World!" // Error: invalid operation: + untyped string
?持?兩個(gè)索引號(hào)返回?串伤塌。?串依然指向原字節(jié)數(shù)組灯萍,僅修改了指針和?度屬性。
s := "Hello, World!"
s1 := s[:5] // Hello ? //索引第一個(gè)元素到第五個(gè)
s2 := s[7:] // World! ? ?//索引第七個(gè)到最后一個(gè)
s3 := s[1:5] // ello
單引號(hào)字符常量表? Unicode Code Point每聪,?持 \uFFFF旦棉、 \U7FFFFFFF、 \xFF 格式药薯。
對(duì)應(yīng) rune 類型绑洛, UCS-4。
func main() {
fmt.Printf("%T\n", 'a')
var c1, c2 rune = '\u6211', '們'
println(c1 == '我', string(c2) == "\xe4\xbb\xac")
}
輸出:
int32 // rune 是 int32 的別名
true true
要修改字符串童本,可先將其轉(zhuǎn)換成 []rune 或 []byte真屯,完成后再轉(zhuǎn)換為 string。?論哪種轉(zhuǎn)
換穷娱,都會(huì)重新分配內(nèi)存讨跟,并復(fù)制字節(jié)數(shù)組。
func main() {
s := "abcd"
bs := []byte(s)
bs[1] = 'B'
println(string(bs)) ? //輸出: ?aBcd
u := "電腦"
us := []rune(u)
us[1] = '話'
println(string(us)) ? ? //電話
}
? for 循環(huán)遍歷字符串時(shí)鄙煤,也有 byte 和 rune 兩種?式晾匠。
func main() {
s := "abc漢字"
for i := 0; i < len(s); i++ { ? // byte
? ? fmt.Printf("%c,", s[i])
}
fmt.Println()
for _, r := range s { ? // rune
fmt.Printf("%c,", r)
}
}
輸出:
a,b,c,?,±,,?,-,,
a,b,c,漢,字,
1.7 指針
?持指針類型 *T,指針的指針 **T梯刚,以及包含包名前綴的 *<package>.T凉馆。
? 默認(rèn)值 nil,沒有 NULL 常量亡资。
? 操作符 "&" 取變量地址澜共, "*" 透過指針訪問?標(biāo)對(duì)象。
? 不?持指針運(yùn)算锥腻,不?持 "->" 運(yùn)算符嗦董,直接? "." 訪問成員
注意: GC 把 uintptr 當(dāng)成普通整數(shù)對(duì)象,它?法阻? "關(guān)聯(lián)" 對(duì)象被回收瘦黑。
1.8 ?定義類型
可將類型分為命名和未命名兩?類京革。命名類型包括 bool、 int幸斥、 string 等匹摇,? array、
slice甲葬、 map 等和具體元素類型廊勃、?度等有關(guān),屬于未命名類型经窖。
Go 學(xué)習(xí)筆記, 第 2 版
18
具有相同聲明的未命名類型被視為同?類型坡垫。
? 具有相同基類型的指針梭灿。
? 具有相同元素類型和?度的 array。
? 具有相同元素類型的 slice冰悠。
? 具有相同鍵值類型的 map堡妒。
? 具有相同元素類型和傳送?向的 channel。
? 具有相同字段序列 (字段名屿脐、類型涕蚤、標(biāo)簽、順序) 的匿名 struct的诵。
? 簽名相同 (參數(shù)和返回值万栅,不包括參數(shù)名稱) 的 function。
? ?法集相同 (?法名西疤、?法簽名相同烦粒,和次序?關(guān)) 的 interface。
var a struct { x int `a` }
var b struct { x int `ab` }
// cannot use a (type struct { x int "a" }) as type struct { x int "ab" } in assignment
b = a
可? type 在全局或函數(shù)內(nèi)定義新類型代赁。
func main() {
type bigint int64
var x bigint = 100
println(x)
}
新類型不是原類型的別名扰她,除擁有相同數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)外,它們之間沒有任何關(guān)系芭碍,不會(huì)持
有原類型任何信息徒役。除??標(biāo)類型是未命名類型,否則必須顯式轉(zhuǎn)換窖壕。
x := 1234
var b bigint = bigint(x) // 必須顯式轉(zhuǎn)換忧勿,除?是常量。
var b2 int64 = int64(b)
var s myslice = []int{1, 2, 3} // 未命名類型瞻讽,隱式轉(zhuǎn)換鸳吸。
var s2 []int = s
最后附上幾個(gè)學(xué)go語言必要的連接