1. 程式人生 > >尹成學院golang學習快速筆記(1)型別

尹成學院golang學習快速筆記(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+l

// (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

println(&s, y)

{

s, z := 1000, 30

println(&s, z)


// 重新賦值: 與前 s 在同⼀層次的程式碼塊中,且有新的變數被定義。

// 通常函式多返回值 err 會被重複使⽤。

// 定義新同名變數: 不在同⼀層次程式碼塊。

}

輸出:

0x2210230f30

0x2210230f3020

0x2210230f1830

1.2常量

常量值必須是編譯期可確定的數字、字串、布林值。

const x, y int = 1, 2

const s = "Hello, World!"

const (

// 多常量初始化

// 型別推斷

// 常量組

a, b

c= 10, 100

bool = false

)

func main() {

const x = "xxx"

// 未使⽤區域性常量不會引發編譯錯誤。

}

不⽀持1UL2LL這樣的型別字尾。

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

const (

s= "abc"

x// x = "abc"

)

 

常量值還可以是lencapunsafe.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 (
_
KB= iota
MB
GB
TB

int64 = 1 << (10 * iota)

// iota = 0

// iota = 1

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

)

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

const (

A, B = iota, iota << 10

C, D

// 0, 0 << 10

// 1, 1 << 10

)

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

const (

A= iota// 0

B= "c" // 1

C= iota// c

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

E // 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) // 常量會被編譯器⾃動轉換。


}




型別

⻓度

預設值

說明

bool

1

false

byte

1

0

uint8

rune

4

0

UnicodeCodePoint,int32

int,uint

48

0

3264

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

48

⾜以儲存指標的uint32uint64整數

array

值型別

struct

值型別

string

""

UTF-8字串

slice

nil

引⽤型別

map

nil

引⽤型別

channel

nil

引⽤型別

interface

nil

接⼝

function

nil

函式


1.3基本型別

明確字型別命名,⽀持Unicode,⽀持常⽤資料結構。

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

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

空指標值nil,⽽⾮C/C++NULL

1.4引⽤型別

引⽤型別包括slicemapchannel。它們有複雜的內部結構,除了申請記憶體外,還需

要初始化相關屬性。

內建函式new計算型別⼤⼩,為其分配零值記憶體,返回指標。⽽make會被編譯器翻譯

成具體的建立函式,由其分配記憶體和初始化成員結構,返回物件⽽⾮指標。


a := []int{0, 0, 0}
a[1] = 10
b := make([]int, 3)
b[1] = 10
c := new([]int)
c[1] = 10

// 提供初始化表示式。
// makeslice
// Error: invalid operation: c[1] (index of type *[]int)


 

1.5型別轉換

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

var b byte = 100

// var n int = b

var n int = int(b)

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

// 顯式轉換


使⽤括號避免優先順序錯誤。

 


*Point(p)

(*Point)(p)

<-chan int(c)

(<-chan int)(c)

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

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


同樣不能將其他型別當bool值使⽤。

a := 100

if a {

println("true")

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

}

1.6字串

字串是不可變值型別,內部⽤指標指向UTF-8位元組陣列。

預設值是空字串""

⽤索引號訪問某位元組,如s[i]

不能⽤序號獲取位元組元素指標,&s[i]⾮法。

不可變型別,⽆法修改位元組陣列。

位元組陣列尾部不包含NULL

//runtime.h

struct String

{



byte*

intgo

str;

len;

};


使⽤索引號問字元(byte)

s := "abc"

println(s[0] == '\x61', s[1] == 'b', s[2] == 0x63)

輸出:

truetruetrue

使⽤"`"定義不做轉義處理的原始字串,⽀持跨⾏。

s := `a

b\r\n\x00

c`

 

println(s)

輸出:

a

b\r\n\x00

c

連線跨⾏字串時,"+"必須在上⼀⾏末尾,否則導致編譯錯誤。

s := "Hello, " +

"World!"

s2 := "Hello, "

+ "World!"

// Error: invalid operation: + untyped string

⽀持⽤兩個索引號返回⼦串。⼦串依然指向原位元組陣列,僅修改了指標和⻓度屬性。

s := "Hello, World!"

s1 := s[:5]
// Hello

s2 := s[7:]

s3 := s[1:5]

// Hello

// World!

// ello



單引號字元常量表⽰UnicodeCodePoint,⽀持\uFFFF\U7FFFFFFF\xFF格式。

對應rune型別,UCS-4

func main() {

fmt.Printf("%T\n", 'a')

 

var c1, c2 rune = '\u6211', '們'

println(c1 == '我', string(c2) == "\xe4\xbb\xac")

}

輸出:

int32

//runeint32的別名

truetrue

要修改字串,可先將其轉換成[]rune[]byte,完成後再轉換為string。⽆論哪種轉

換,都會重新分配記憶體,並複製位元組陣列。

func main() {

s := "abcd"

bs := []byte(s)

bs[1] = 'B'

println(string(bs))

u := "電腦"

us := []rune(u)

us[1] = '話'

println(string(us))

}

輸出:

aBcd

電話

for迴圈遍歷字串時,也有byterune兩種⽅式。

 

 

func main() {

s := "abc漢字"

for i := 0; i < len(s); i++ {

fmt.Printf("%c,", s[i])

}

fmt.Println()

for _, r := range s {

fmt.Printf("%c,", r)

}

// byte

// rune

}

輸出:

a,b,c,æ,±,,å,­,,

a,b,c,,,

1.7指標

⽀持指標型別*T,指標的指標**T,以及包含包名字首的*<package>.T

預設值nil,沒有NULL常量。

操作符"&"取變數地址,"*"透過指標訪問⺫標物件。

不⽀持指標運算,不⽀持"->"運算子,直接⽤"."訪問⺫標成員。

func main() {

type data struct{ a int }

var d = data{1234}

var p *data

p = &d

fmt.Printf("%p, %v\n", p, p.a)

}

輸出:

0x2101ef018,1234

不能對指標做加減法等運算。

 

x := 1234

p := &x

// 直接⽤指標訪問⺫標物件成員,⽆須轉換。


 


p++


// Error: invalid operation: p += 1 (mismatched types *int and int)

可以在unsafe.Pointer和任意型別指標間進⾏轉換。

func main() {

x := 0x12345678

p := unsafe.Pointer(&x)

n := (*[4]byte)(p)

for i := 0; i < len(n); i++ {

fmt.Printf("%X ", n[i])

}

// *int -> Pointer

// Pointer -> *[4]byte

}

輸出:

78563412

返回區域性變數指標是安全的,編譯器會根據需要將其分配在GCHeap上。

func test() *int {

x := 100

return &x


// 在堆上分配 x 記憶體。但在內聯時,也可能直接分配在⺫標棧。



}

 

Pointer轉換成uintptr,可變相實現指標運算。

func main() {

d := struct {

s

x


string

int

}{"abc", 100}

p := uintptr(unsafe.Pointer(&d))

p += unsafe.Offsetof(d.x)

// *struct -> Pointer -> uintptr

// uintptr + offset

p2 := unsafe.Pointer(p)

px := (*int)(p2)

*px = 200

fmt.Printf("%#v\n", d)

// uintptr -> Pointer

// Pointer -> *int

// d.x = 200

}

輸出:

struct{sstring;xint}{s:"abc",x:200}

注意:GCuintptr當成普通整數物件,它⽆法阻⽌"關聯"物件被回收。

1.8⾃定義型別

可將型別分為命名和未命名兩⼤類。命名型別包括boolintstring等,⽽array

slicemap等和具體元素型別、⻓度等有關,屬於未命名型別。

具有相同宣告的未命名型別被視為同⼀型別。

具有相同基型別的指標。

具有相同元素型別和⻓度的array

具有相同元素型別的slice

具有相同鍵值型別的map

具有相同元素型別和傳送⽅向的channel

具有相同欄位序列(欄位名、型別、標籤、順序)的匿名struct

簽名相同(引數和返回值,不包括引數名稱)function

⽅法集相同(⽅法名、⽅法簽名相同,和次序⽆關)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在全域性或函式內定義新型別。

func main() {

type bigint int64

 

var x bigint = 100

println(x)

}



新型別不是原型別的別名,除擁有相同資料儲存結構外,它們之間沒有任何關係,不會持

有原型別任何資訊。除⾮⺫標型別是未命名型別,否則必須顯式轉換。

x := 1234

var b bigint = bigint(x)

var b2 int64 = int64(b)

var s myslice = []int{1, 2, 3}

var s2 []int = s

// 必須顯式轉換,除⾮是常量。

// 未命名型別,隱式轉換。


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







網址:http://www.qukuailianxueyuan.io/



欲領取造幣技術與全套虛擬機器資料

區塊鏈技術交流QQ群:756146052  備註:CSDN

尹成學院微信:備註:CSDN




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




網址:http://www.qukuailianxueyuan.io/



欲領取造幣技術與全套虛擬機器資料

區塊鏈技術交流QQ群:756146052  備註:CSDN

尹成學院微信:備註:CSDN