這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Golang 語言基礎之六: string, pointer
Golang 語言基礎系列:
- Golang 語言基礎之一: type, variable, constant
- Golang 語言基礎之二: for, ifelse, switch
- Golang 語言基礎之三: array, slice
- Golang 語言基礎之四: map, range
- Golang 語言基礎之五: function
- Golang 語言基礎之六: string, pointer
- Golang 語言基礎之七: struct, method
- Golang 語言基礎之八: interface
- Golang 語言基礎之九: error, panic, recover
- Golang 語言基礎之十: goroutine, channel
字串類型 string
字串在 Golang 源碼檔案 runtime.h 中的定義如下:
struct String{byte* str;intgo len;};
可以看出,其內部包含一個 byte 類型的數組,Golang 採用 UTF-8 編碼方式。和 C/C++ 的字元數組不同,Golang 的字元數組有下面的特點:
string 類型的零值為空白字串。
- 不能用序號擷取位元組元素指標,&s[i] 為非法。
string 是不可變類型,其內部儲存資料的字元數組無法修改。如需修改,需要將 string 對象轉化為 rune 類型(如果字串含有非 ASIC 碼字元)或者 byte 類型(如果字串由 ASIC 碼字元組成)的 slice 對象。修改後的字元數組會重新分配記憶體儲存在一個新的字串對象中。
- 位元組數組尾部不包含
\0
關於 string 的使用方法我們看個例子:
package mainimport "fmt"func main() {// 預設 string 類型對象零值為空白字串,尾部不包含 `\0`var emptyStr stringfmt.Println("emptyStr is: ", emptyStr)fmt.Println("len(emptyStr) is: ", len(emptyStr))// 聲明 string 對象並初始化,使用下標訪問。// 注意,如果字串中包含中文等非 ASIC 碼的字元,則使用下標索引會導致與期望不符的結果// 字串是 UTF-8 編碼,所以非 ASIC 碼字元不止一個位元組,而使用下標獲得的是每個位元組的內容。str := "I like 高圓圓"fmt.Println("string object is: ", str)fmt.Println("len(str) = : ", len(str))fmt.Println("str[1]: ", str[1])// 使用 ` 文法可以聲明無轉義的字串str = `ILoveGolang`fmt.Println("str: ", str)// 修改字串,注意將字串分別轉化為 `rune` 和 `byte` 的 `slice` 對象。// 它們的長度是不相等的,`rune` 切片對象的長度等於原始 `string` 對象中的字元個數。// `byte` 切片對象的長度等於原始 `string` 對象在記憶體中所佔的位元組數,其值和 `len` 取得的 `string` 對象長度相等// 如果 `string` 對象中有非 ASIC 碼,則兩者的長度是不相等的。// 所以為了保證相容性,最好將 `string` 對象轉化為 `rune` 切片對象後進行修改。str = "I like 高圓圓"fmt.Println("Before modification, str: ", str)fmt.Println("len(str) = : ", len(str))rune_str := []rune(str)byte_str := []byte(str)fmt.Println("len([]rune(str)) = ", len(rune_str))fmt.Println("len([]byte(str)) = ", len(byte_str))rune_str[7] = '範'rune_str[8] = '冰'rune_str[9] = '冰'fmt.Println("After modification, str: ", string(rune_str))// 單引號中的字元常量為 `rune` 類型,取類型後為 int32v_char := 'g'fmt.Printf("The type of v_char is %T\n", v_char)}
將上面的代碼存入源檔案 string.go 並使用 go run string.go 可以看到下面的輸入:
emptyStr is: len(emptyStr) is: 0string object is: I like 高圓圓len(str) = : 16str[1]: 32str: I Love GolangBefore modification, str: I like 高圓圓len(str) = : 16len([]rune(str)) = 10len([]byte(str)) = 16After modification, str: I like 範冰冰The type of v_char is int32
指標類型 pointer
Golang 中的指標和 C/C++ 相同的地方有:
- 指標 *T
- 指標的指標 **T
- 通過 operator
* 訪問指標指向的對象,& 取對象的地址
不同的地方有:
- 指標的預設值為
nil,而不是 NULL
- 指標不能進行加減運算,指標所指對象的成員使用
. 訪問而非 ->
- 使用
unsafe.Pointer 可以對指向不同類型對象的指標進行轉換
- 指標不能進行
+、- 運算,以保證安全性。
使用執行個體如下:
package mainimport ("fmt""unsafe")func main() {// 檢查指標對象的零值為 nilvar p *intfmt.Println("The zero value of a pointer is: ", p)// 指向指標的指標pp := &pfmt.Printf("The type of a pointer points another pointer is: %T\n", pp)// 指標對象賦值intVar := 100000000p = &intVarfmt.Println("After assignment, p is: ", p)fmt.Println("The value pointer p points is: ", *p)// 使用 unsafe.Pointer 方法可以將一個類型的指標轉化為 Pointer// Pointer 可以被轉化為任意類型的指標。// 注意由於 int 為 int32 的別名,占 4 個位元組,所以我們將其轉化為含有 4 個位元組元素的 `byte` 數組指標var strP *[4]bytestrP = (*[4]byte)(unsafe.Pointer(p))fmt.Println("After \"(*[4]byte)(unsafe.Pointer(p))\", *[4]byte pointer strP is: ", strP)fmt.Println("After \"(*[4]byte)(unsafe.Pointer(p))\", *[4]byte pointer strP points to: ", *strP)// 指標指向的對象內容使用 `.` 而不是 `->` 來進行訪問type User struct {name string}userP := &User{"Xiaohui",}fmt.Println("Before change, The value userP points to is: ", *userP)userP.name = "Ross"fmt.Println("After change, The value userP points to is: ", *userP)}
將上面的代碼存入源檔案 pointer.go 並使用 go run pointer.go 可以看到下面的輸入:
The zero value of a pointer is: <nil>The type of a pointer points another pointer is: **intAfter assignment, p is: 0xc20800a240The value pointer p points is: 100000000After "(*[4]byte)(unsafe.Pointer(p))", *[4]byte pointer strP is: &[0 225 245 5]After "(*[4]byte)(unsafe.Pointer(p))", *[4]byte pointer strP points to: [0 225 245 5]Before change, The value userP points to is: {Xiaohui}After change, The value userP points to is: {Ross}
關於 unsafe.Pointer,建議閱讀這篇文章,裡面做了很好的總結。
參考資料
- The Go Programming Language
- 學習 Go 語言 中文版
- Go in Action 中文版
- The way to Go 中文版
- Go by Example
- Organizing Go code
- Testing Techniques
- Go 語言分享
- Go 學習筆記
- Go 語言簡介
- Tony Bai 的部落格
-- EOF --
- Golang 語言基礎之五: function→
- ← Golang 語言基礎之七: struct, method
聲明: 本文採用 BY-NC-SA 協議進行授權. 轉載請註明轉自: Golang 語言基礎之六: string, pointer