這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。Go 有指標,但是沒有指標運算。你不能用指標變數遍曆字串的各個位元組.通過類型作為首碼來定義一個指標’*’:var p *int。現在p 是一個指向整數值的指標。所有新定義的變數都被賦值為其類型的零值,而指標也一樣。一個新定義的或者沒有任何指向的指標,有值nil。在其他語言中,這經常被叫做空(NULL)指標,在Go 中就是nil。讓指標指向某些內容,可以使用取址操作符(&)
如果一個method的receiver是*T,你可以在一個T類型的執行個體變數V上面調用這個method,而不需要&V去調用這個method類似的如果一個method的receiver是T,你可以在一個*T類型的變數P上面調用這個method,而不需要 *P去調用這個method
例1:package mainimport "fmt"func main(){ var p *int fmt.Printf("%v\n", p) var i int p = &i fmt.Printf("%v\n", p)}
輸出結果:<nil>0x18600118
例2:package mainimport "fmt"func main(){ var p *int var i int p = &i *p = 8 fmt.Printf("%v\n", *p) fmt.Printf("%v\n", i)}輸出結果:88
因為Go沒有指標運算,所以如果這樣寫:*p++,它表示(*p)++:首先擷取指標指向的值,然後對這個值加一。
Go 有兩個記憶體配置原語,new 和make
1、用new 分配記憶體它返回了一個指標,指向新分配的類型T 的零值。
2、用make 分配記憶體內建函數make(T, args) 與new(T) 有著不同的功能。它只能建立slice,map和channel,並且返回一個有初始值(非零)的T 類型,而不是*T。
new(T) 返回*T 指向一個零值Tmake(T) 返回初始化後的T
定義自己的類型Go 允許定義新的類型,通過保留字type 實現:type foo int建立了一個新的類型foo 作用跟int 一樣。建立更加複雜的類型需要用到struct 保留字。
例:package mainimport "fmt"type NameAge struct { name string //不匯出 age int //不匯出}func main(){ a := new(NameAge) a.name = "Pete" a.age = 42 fmt.Printf("%v\n", a) fmt.Printf("%v\n", a.name)}輸出結果:&{Pete 42}Pete
注意struct{}中首字母大寫的欄位可以被匯出,也就是說,在其他包中可以進行讀寫。欄位名以小寫字幕開頭是當前包的私人的。
例2:
type person struct { name string age int}var P person // P現在就是person類型的變數了P.name = "Astaxie" // 賦值"Astaxie"給P的name屬性.P.age = 25 // 賦值"25"給變數P的age屬性fmt.Printf("The person's name is %s", P.name) // 訪問P的name屬性.
除了上面這種P的聲明使用之外,還有兩種聲明使用方式
例3:package mainimport "fmt"
// 聲明一個新的類型type person struct { name string age int}
// 比較兩個人的年齡,返回年齡大的那個人,並且返回年齡差// 注意:struct也是傳值的func Older(p1, p2 person) (person, int) { if p1.age>p2.age { // 比較p1和p2這兩個人的年齡 return p1, p1.age-p2.age } return p2, p2.age-p1.age}
func main() { var tom person // 賦值初始化 tom.name, tom.age = "Tom", 18
// 兩個欄位都寫清楚的初始化 bob := person{age:25, name:"Bob"}
// 按照struct定義順序初始化值 paul := person{"Paul", 43}
tb_Older, tb_diff := Older(tom, bob) tp_Older, tp_diff := Older(tom, paul) bp_Older, bp_diff := Older(bob, paul)
fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, bob.name, tb_Older.name, tb_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, paul.name, tp_Older.name, tp_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n", bob.name, paul.name, bp_Older.name, bp_diff)}輸出結果:Of Tom and Bob, Bob is older by 7 yearsOf Tom and Paul, Paul is older by 25 yearsOf Bob and Paul, Paul is older by 18 years
struct的匿名欄位
我們上面介紹了如何定義一個struct,定義的時候是欄位名與其類型一一對應,實際上Go支援只提供類型,而不寫欄位名的方式,也就是匿名欄位,也稱為嵌入欄位。當匿名欄位是一個struct的時候,那麼這個struct所擁有的全部欄位都被隱式地引入了當前定義的這個struct。
例:package mainimport "fmt"
type Human struct { name string age int weight int}
type Student struct { Human // 匿名欄位,那麼預設Student就包含了Human的所有欄位 speciality string}
func main() { // 我們初始化一個學生 mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
// 我們訪問相應的欄位 fmt.Println("His name is ", mark.name) fmt.Println("His age is ", mark.age) fmt.Println("His weight is ", mark.weight) fmt.Println("His speciality is ", mark.speciality) // 修改對應的備忘資訊 mark.speciality = "AI" fmt.Println("Mark changed his speciality") fmt.Println("His speciality is ", mark.speciality) // 修改他的年齡資訊 fmt.Println("Mark become old") mark.age = 46 fmt.Println("His age is", mark.age) // 修改他的體重資訊 fmt.Println("Mark is not an athlet anymore") mark.weight += 60 fmt.Println("His weight is", mark.weight)}輸出結果:His name is MarkHis age is 25His weight is 120His speciality is Computer ScienceMark changed his specialityHis speciality is AIMark become oldHis age is 46Mark is not an athlet anymoreHis weight is 180
方法可以對新定義的類型創先函數以便操作,可以通過兩種途徑:1. 建立一個函數接受這個類型的參數。 func doSomething(in1 *NameAge, in2 int) { /* ... */ } (你可能已經猜到了)這是函數調用。2. 建立一個工作在這個類型上的函數(參閱在3.1 中定義的接收方): func (in1 *NameAge) doSomething(in2 int) { /* ... */ } 這是方法調用,可以類似這樣使用: var n *NameAge n.doSomething(2)
例1:package mainimport "fmt"type NameAge struct { name string age int}func main(){ a := new(NameAge) a.name = "Pete" a.age = 42 doSomething(a, 3)}func doSomething(in1 *NameAge, in2 int){ fmt.Printf("%v\n", in1.name) fmt.Printf("%d\n", in2)}輸出結果:Pete3
例2:package mainimport "fmt"type NameAge struct { name string age int}func main(){ a := new(NameAge) a.name = "Pete" a.age = 42 a.doSomething(333)}func (in1 *NameAge) doSomething(in2 int){ fmt.Printf("%v\n", in1.name) fmt.Printf("%d\n", in2)}輸出結果:Pete333
類型轉換有時需要將一個類型轉換為另一個類型。在Go 中可以做到,不過有一些規則。
注意Go 的字串是UTF-8 編碼的,一些字元可能是1、2、3 或者4 個位元組結尾。
例:package mainimport "fmt"func main(){ mystring := "hello world" byteslice := []byte(mystring) for _, val := range byteslice { fmt.Printf("%v\n", val) }}輸出結果:10410110810811132119111114108100
例2package mainimport "fmt"func main(){ mystring := "hello world" byteslice := []rune(mystring) for _, val := range byteslice { fmt.Printf("%c\n", val) }}輸出結果:hello
world對於數值,定義了下面的轉換:• 將整數轉換到指定的(bit)長度:uint8(int);• 從浮點數到整數:int(float32)。這會截斷浮點數的小數部分;• 其他的類似:float32(int)。例:package mainimport "fmt"func main(){ myfloat := 123.72 myint := int(myfloat) fmt.Printf("%.3f\n", myfloat) fmt.Printf("%d\n", myint)}輸出結果:123.720123
使用者定義型別的轉換如何在自訂類型之間進行轉換?這裡建立了兩個類型Foo 和Bar,而Bar 是Foo 的一個別名:type foo struct { int } 匿名欄位type bar foo bar 是foo 的別名然後:var b bar = bar{1} 聲明b 為bar 類型var f foo = b 賦值b 到f最後一行會引起錯誤:cannot use b (type bar) as type foo in assignment(不能使用b(類型bar)作為類型foo 賦值)這可以通過轉換來修複:var f foo = foo(b)注意轉換那些欄位不一致的結構是相當困難的。同時注意,轉換b 到int 同樣會出錯;整數與有整數欄位的結構並不一樣。
例:package mainimport "fmt"type foo struct { int } //匿名欄位type bar foofunc main(){ b := bar{1} //聲明b 為bar 類型,並賦初值 var f foo = b //上面賦值b 到f,這會引起一行錯誤cannot use b (type bar) as type foo in assignment(不能使用b(類型bar)作為類型foo 賦值) var f foo = foo(b) //這個是可以的 fmt.Printf("%d\n", f)}輸出結果:{1}
注意:轉換b 到int 同樣會出錯;整數與有整數欄位的結構並不一樣。