天天看點

go 類型(第 1 章 )

1.1 變量

Go 是靜态類型語⾔,不能在運⾏期改變變量類型。

使⽤關鍵字 var 定義變量,⾃動初始化為零值。如果提供初始化值,可省略變量類型,由

編譯器⾃動推斷。

var x int

var f float32 = 1.6

var s = "abc"

在函數内部,可⽤更簡略的 ":=" ⽅式定義變量。

func main() {

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

}

可⼀次定義多個變量。

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)

}

多變量指派時,先計算所有相關值,然後再從左到右依次指派。

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)

}

編譯器會将未使⽤的局部變量當做錯誤。

var s string // 全局變量沒問題。

func main() {

 i := 0 // Error: i declared and not used。(可使⽤ "_ = i" 規避)

}

注意重新指派與定義新同名變量的差別。

s := "abc"

println(&s)

s, y := "hello", 20 // 重新指派: 與前 s 在同⼀層次的代碼塊中,且有新的變量被定義。

println(&s, y) // 通常函數多傳回值 err 會被重複使⽤。

{

 s, z := 1000, 30 // 定義新同名變量: 不在同⼀層次代碼塊。

 println(&s, z)

}

輸出:

0x2210230f30

0x2210230f30 20

0x2210230f18 30

1.2 常量

常量值必須是編譯期可确定的數字、字元串、布爾值。

const x, y int = 1, 2 // 多常量初始化

const s = "Hello, World!" // 類型推斷

const ( // 常量組

 a, b = 10, 100

 c bool = false

)

func main() {

 const x = "xxx" // 未使⽤局部常量不會引發編譯錯誤。

}

不⽀持 1UL、2LL 這樣的類型字尾。

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

const (

 s = "abc"

 x // x = "abc"

)

常量值還可以是 len、cap、unsafe.Sizeof 等編譯期可确定結果的函數傳回值。

const (

 a = "abc"

 b = len(a)

 c = unsafe.Sizeof(b)

)

如果常量類型⾜以存儲初始化值,那麼不會引發溢出錯誤。

const (

 a byte = 100 // int to byte

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

)

枚舉

關鍵字 iota 定義常量組中從 0 開始按⾏計數的⾃增枚舉值。

const (

 Sunday = iota // 0

 Monday // 1,通常省略後續⾏表達式。

 Tuesday // 2

 Wednesday // 3

 Thursday // 4

 Friday // 5

 Saturday // 6

)

const (

 _ = iota // iota = 0

 KB int64 = 1 << (10 * iota) // iota = 1

 MB // 與 KB 表達式相同,但 iota = 2

 GB

 TB

)

在同⼀常量組中,可以提供多個 iota,它們各⾃增⻓。

const (

 A, B = iota, iota << 10 // 0, 0 << 10

 C, D // 1, 1 << 10

)

如果 iota ⾃增被打斷,須顯式恢複。

const (

 A = iota // 0

 B // 1

 C = "c" // c 

 D // c,與上⼀⾏相同。

 E = iota // 4,顯式恢複。注意計數包含了 C、D 兩⾏。

 F // 5

)

可通過⾃定義類型來實作枚舉類型限制。

type Color int

const (

 Black Color = iota

 Red

 Blue

)

func test(c Color) {}

func main() {

 c := Black

 test(c)

 x := 1

 test(x) // Error: cannot use x (type int) as type Color in function argument

 test(1) // 常量會被編譯器⾃動轉換。

}

1.3 基本類型

更明确的數字類型命名,⽀持 Unicode,⽀持常⽤資料結構。

類型 ⻓度 預設值 說明

bool 1 false

byte 1 0 uint8

rune 4 0 Unicode Code Point, int32

int, uint 4 或 8 0 32 或 64 位

int8, uint8 1 0 -128 ~ 127, 0 ~ 255

int16, uint16 2 0 -32768 ~ 32767, 0 ~ 65535

int32, uint32 4 0 -21億 ~ 21 億, 0 ~ 42 億

int64, uint64 8 0

float32 4 0.0

float64 8 0.0

complex64 8

complex128 16

uintptr 4 或 8 ⾜以存儲指針的 uint32 或 uint64 整數

array 值類型

struct 值類型

string "" UTF-8 字元串

slice nil 引⽤類型

map nil 引⽤類型

channel nil 引⽤類型

interface nil 接⼝

function nil 函數

⽀持⼋進制、⼗六進制,以及科學記數法。标準庫 math 定義了各數字類型取值範圍。

a, b, c, d := 071, 0x1F, 1e9, math.MinInt16

空指針值 nil,⽽⾮ C/C++ NULL。

1.4 引⽤類型

引⽤類型包括 slice、map 和 channel。它們有複雜的内部結構,除了申請記憶體外,還需

要初始化相關屬性。

内置函數 new 計算類型⼤⼩,為其配置設定零值記憶體,傳回指針。⽽ make 會被編譯器翻譯

成具體的建立函數,由其配置設定記憶體和初始化成員結構,傳回對象⽽⾮指針。

a := []int{0, 0, 0} // 提供初始化表達式。

a[1] = 10

b := make([]int, 3) // makeslice

b[1] = 10

c := new([]int)

c[1] = 10 // Error: invalid operation: c[1] (index of type *[]int)

有關引⽤類型具體的記憶體布局,可參考後續章節。

1.5 類型轉換

不⽀持隐式類型轉換,即便是從窄向寬轉換也不⾏。

var b byte = 100

// var n int = b // Error: cannot use b (type byte) as type int in assignment

var n int = int(b) // 顯式轉換

使⽤括号避免優先級錯誤。

*Point(p) // 相當于 *(Point(p))

(*Point)(p)

<-chan int(c) // 相當于 <-(chan int(c))

(<-chan int)(c)

同樣不能将其他類型當 bool 值使⽤。

a := 100

if a { // Error: non-bool a (type int) used as if condition

 println("true")

}