第 1 章 類型介紹

1.1 變量

Go 是靜態(tài)類型語?,不能在運?期改變變量類型。

使?關(guān)鍵字 var 定義變量,?動初始化為零值。如果提供初始化值,可省略變量類型,由編譯器?動推斷。

var a int

var f float32 = 1.6

var s = "abc" ?//編譯器自動推導(dǎo)類型

在函數(shù)內(nèi)部,可?更簡略的 ":=" ?式定義變量,自動推導(dǎo)類型。

func main() {

x := 66 ?// 注意檢查,是定義新局部變量,還是修改全局變量。該?式容易造成錯誤。

//x:=22 ?//在一個main函數(shù)里定義過的類型,不能再使用這種方式

}

可?次定義多個變量。

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) ?//打印時自動換行

}

多變量賦值時,先計算所有相關(guān)值,然后再從左到右依次賦值。

data, i := [3]int{0, 1, 2}, 0

i, data[i] = 2, 100 // (i = 0) -> (i = 2), (data[0] = 100)

?_ ?實際上是一個只寫變量,你不能得到它的值,不能讀,?于忽略值,占位


func test() (int, string) {

return 1, "abc"

}

func main() {

_,s := test() ? //接受一個返回值,忽略一個

println(s)

}

編譯器會將未使?的局部變量當(dāng)做錯誤。

import(

"fmt" ?//導(dǎo)入一個輸入輸出的包,

_"fmt" ?//如果不使用,可以前面加上 _ ?,不然編譯器會報錯

)

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 會被重復(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" // 未使?局部常量不會引發(fā)編譯錯誤。

}

不?持 1UL、 2LL 這樣的類型后綴。

在常量組中,如不提供類型和初始化值,那么視作與上?常量相同。

const (

s = "abc"

x // x = "abc"

)

常量值還可以是 len、 cap、 unsafe.Sizeof 等編譯期可確定結(jié)果的函數(shù)返回值,

不能將函數(shù)的返回值賦給常量,因為函數(shù)調(diào)用發(fā)生在運行期

const (

a = "abc"

b = len(a)

c = unsafe.Sizeof(b)

)

如果常量類型?以存儲初始化值,那么不會引發(fā)溢出錯誤。

const (

a byte = 100 // int to byte

b int = 1e20 // float64 to int, overflows

)

枚舉

關(guān)鍵字 iota 定義常量組中從 0 開始按?計數(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

)

在同?常量組中,可以提供多個 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ù)。注意計數(shù)包含了 C、 D 兩?。

F // 5

)


package main

import "fmt"

func main() {

const (

? ? ?a = iota //0

? ? ?b //1

? ? ?c //2

? ? ?d = "ha" //獨?值, iota += 1

? ? ?e //"ha" iota += 1?

? ? ?f = 100 //iota +=1

? ? ?g //100 iota +=1

? ? ?h = iota //7,恢復(fù)計數(shù)

? ? ?i //8

)

fmt.Println(a, b, c, d, e, f, g, h, i)

}

以上實例運行結(jié)果為:

0 1 2 ha ha 100 100 7 8



1.3 基本類型

更明確的數(shù)字類型命名,?持 Unicode,?持常?數(shù)據(jù)結(jié)構(gòu)。序號類型和描述

1布爾型

布爾型的值只可以是常量 true 或者 false。一個簡單的例子:var b bool = true。

2數(shù)字類型

整型 int 和浮點型 float32、float64,Go 語言支持整型和浮點型數(shù)字,并且原生支持復(fù)數(shù),其中位的運算采用補(bǔ)碼。

3字符串類型:

字符串就是一串固定長度的字符連接起來的字符序列。Go的字符串是由單個字節(jié)連接起來的。Go語言的字符串的字節(jié)使用UTF-8編碼標(biāo)識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),除了申請內(nèi)存外,還需

要初始化相關(guān)屬性。

內(nèi)置函數(shù) new 計算類型??,為其分配零值內(nèi)存,返回指針。? make 會被編譯器翻譯

成具體的創(chuàng)建函數(shù),由其分配內(nèi)存和初始化成員結(jié)構(gòu),返回對象??指針。

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)換

使?括號避免優(yōu)先級錯誤。

*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)值是空字符串 ""。

? ?索引號訪問某字節(jié),如 s[i]。

? 不能?序號獲取字節(jié)元素指針。 &s[i] ?法。

? 不可變類型,?法修改字節(jié)數(shù)組。

? 字節(jié)數(shù)組尾部不包含 NULL。

使?索引號訪問字符 (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

連接跨?字符串時, "+" 必須在上??末尾,否則導(dǎo)致編譯錯誤。

s := "Hello, " + ? ?//必須加在上一行結(jié)尾

"World!"

s2 := "Hello, "

+ "World!" // Error: invalid operation: + untyped string

?持?兩個索引號返回?串。?串依然指向原字節(jié)數(shù)組,僅修改了指針和?度屬性。

s := "Hello, World!"

s1 := s[:5] // Hello ? //索引第一個元素到第五個

s2 := s[7:] // World! ? ?//索引第七個到最后一個

s3 := s[1:5] // ello

單引號字符常量表? Unicode Code Point,?持 \uFFFF、 \U7FFFFFFF、 \xFF 格式。

對應(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)

換,都會重新分配內(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)遍歷字符串時,也有 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)對象。

? 不?持指針運算,不?持 "->" 運算符,直接? "." 訪問成員


注意: GC 把 uintptr 當(dāng)成普通整數(shù)對象,它?法阻? "關(guān)聯(lián)" 對象被回收。



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ù)存儲結(jié)構(gòu)外,它們之間沒有任何關(guān)系,不會持

有原類型任何信息。除??標(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



最后附上幾個學(xué)go語言必要的連接

golang標(biāo)準(zhǔn)庫文檔

go語言中文網(wǎng)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容