您好,登錄后才能下訂單哦!
從如下幾個方面介紹GO語言的數據
1. 字符串 2. 數組 3. 切片 4. 字典 5. 結構
Go語言中的字符串是由一組不可變的字節(byte)序列組成從源碼文件中看出其本身是一個復合結構
string.go type stringStruct struct { str unsafe.Pointer len int }
字符串中的每個字節都是以UTF-8編碼存儲的Unicode字符字符串的頭部指針指向字節數組的開始但是沒有NULL或'\0'結尾標志。 表示方式很簡單用雙引號("")或者反引號(``)它們的區別是
雙引號之間的轉義符會被轉義而反引號之間的轉義符保持不變
反引號支持跨行編寫而雙引號則不可以
{ println("hello\tgo") //輸出hello go println(`hello\tgo`) //輸出hello\tgo } { println( "hello go" )//syntax error: unexpected semicolon or newline, expecting comma or ) println(`hello go`) //可以編譯通過 } 輸出 hello go
在前面類型的章節中描述過字符串的默認值是""而不是nil,比如
var s string println( s == "" ) //true println( s == nil ) //invalid operation: s == nil (mismatched types string and nil)
Go字符串支持 "+ , += , == , != , < , >" 六種運算符
Go字符串允許用索引號訪問字節數組(非字符)但不能獲取元素的地址比如
{ var a = "hello" println(a[0]) //輸出 104 println(&a[1]) //cannot take the address of a[1] }
Go字符串允許用切片的語法返回子串(起始和結束索引號)比如
var a = "0123456" println(a[:3]) //0,1,2 println(a[1:3]) //1,2 println(a[3:]) //3,4,5,6
日常開發中經常會有遍歷字符串的場景比如
{ var a = "Go語言" for i:=0;i < len(a);i++{ //以byte方式按字節遍歷 fmt.Printf("%d: [%c]\n", i, a[i]) } for i, v := range a{ //以rune方式遍歷 fmt.Printf("%d: [%c]\n", i, v) } } 輸出 0: [G] 1: [o] 2: [è] 3: [ˉ] 4: [-] 5: [è] 6: [¨] 7: [] 0: [G] 1: [o] 2: [語] 5: [言]
在Go語言中字符串的底層使用的是不可以改變的byte數組存的所以在用byte輪詢方式時每次得到的只有一個byte而中文字符則是占3個byte的。rune采用計算字符串長度的方式與byte方式不同比如
println(utf8.RuneCountInString(a)) // 結果為 4 println(len(a)) // 結果為 8
所以如果想要獲得期待的那種結果的話需要先將字符串a轉換為rune切片再使用內置的len函數比如:
{ r := []rune(a) for i:= 0;i < len(r);i++{ fmt.Printf("%d: [%c]\n", i, r[i]) } }
所以在遍歷或處理的字符串的情況下如果其中存在中文盡量使用rune方式處理。
轉換
前面講過不能修改原字符串如果修改的話需要將字符串轉換成[]byte或[]rune , 然后在轉換回來比如
{ var a = "hello go" a[1] = 'd' //cannot assign to a[1] } { var a = "hello go" bs := []byte(a) ... s2 := string(bs) rs := []rune(a) ... s3 := string(rs) }
Go語言支持用"+"運算符進行字符串拼接但是每次拼接都需要重新分配內存如果頻繁構造一個很長的字符串則性能影響就會很大比如
func test1()string{ var s string for i:= 0;i < 1000 ;i++{ s += "a" } return s } func Benchmark_test1(b *testing.B){ for i:= 0;i < b.N; i++{ test1() } } 輸出 # go test str1_b_test.go -bench="test1" -benchmem Benchmark_test1-2 5000 227539 ns/op 530338 B/op 999 allocs/op
常用的改進方法是預分配足夠的內存空間然后使用strings.Join函數該函數會統計出所有參數的長度并一次性完成內存分配操作改進一下上面的代碼
func test()string{ s := make([]string,1000) for i:= 0;i < 1000 ;i++{ s[i] = "a" } return strings.Join(s,"") } func Benchmark_test(b *testing.B){ for i:= 0;i < b.N; i++{ test() } } 輸出 # go test -v b_test.go -bench="test1" -benchmem Benchmark_test1-2 200000 10765 ns/op 2048 B/op 2 allocs/op
在日常開發中可以使用fmt.Sprintf函數來格式化和拼接較少的字符串操作比如
{ a := 10010 as := fmt.Sprintf("%d",a) fmt.Printf("%T , %v\n",as,as) }
數組
數組是內置(build-in)類型是一組存放相同類型數據的集合數組的數據類型是由存儲的元素類型和數組的長度共同決定的,即使元素類型相同但是長度不同數組也不屬于同一類型。數組初始化之后長度是固定無法修改的數組也支持邏輯判斷運算符 "==","="定義方式如下
{ var a [10]int var b [20]int println(a == b) //invalid operation: a == b (mismatched types [10]int and [20]int) }
數組的初始化相對靈活下標索引值從0開始支持按索引位置初始化對于未初始化的數組編譯器將給以默認值。
{ var a[4] int //元素初始化為0 b := [4] int{0,1} //未初始化的元素將被初始化為0 c := [4] int{0, 2: 3} //可指定索引位置初始化 d := [...]int{0,1,2} //編譯器根據初始化值數量來確定數組的長度 e := [...]int{1, 3:3} //支持索引位置初始化但數組長度與其無關 type user struct{ name string age int } d := [...] user{ //復合數據類型數組可省略元素初始化類型標簽 {"a",1}, {"b",2}, } }
定義多維數組時只有數組的第一維度允許使用 "..."
{ x := [2]int{2,2} a := [2][2]int{{1,2},{2,2}} b := [...][2]int{{2,3},{2,2},{3,3}} c := [...][2][2]int{{ {2,3},{2,2} },{{3,3},{4,4}} } }
計算數組長度時無論使用內置的len還是cap返回的都是第一維度的長度比如
{ fmt.Println(x, len(x), cap(x)) fmt.Println(a, len(a), cap(x)) fmt.Println(b, len(b), cap(x)) fmt.Println(c, len(c), cap(x)) } 輸出 [2 2] 2 2 [[1 2] [2 2]] 2 2 [[2 3] [2 2] [3 3]] 3 2 [[[2 3] [2 2]] [[3 3] [4 4]]] 2 2
數組指針&指針數組
數組除了可以存放具體類型的數據也可以存放指針比如
{ x, y := 10, 20 a := [...]*int{&x, &y} //指針數組 p := &a //數組的指針 }
數組復制
Go語言數組是值(非引用)類型所以在賦值和參數傳遞過程中都會復制整個數組數據比如:
func test(x [2]int){ fmt.Printf("x:= %p,%v\n", &x, x) } func main(){ a := [2] int{1, 2} test(a) //傳參過程中完全復制 var b [2]int b = a //賦值過程中完全復制 fmt.Printf("a:= %p,%v\n", &a, a) fmt.Printf("b:= %p,%v\n", &b, b) } 輸出 x:= 0xc42000a330,[1 2] a:= 0xc42000a320,[1 2] b:= 0xc42000a370,[1 2]
借鑒: 雨痕<GO學習筆記>
討論學習: 675020908
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。