更多個人筆記見:
github個人筆記倉庫
gitee 個人筆記倉庫
個人學習,學習過程中還會不斷補充~ (后續會更新在github上)
文章目錄
- stirng 字符串
- 區分 rune,byte,string
- 字符串操作
- strings 庫相關
- fmt.Printf語法
- Slice 切片
- 基礎知識
- 數組和切片的區別
- append函數
- 通過append看切片和擴容
- 通過 append 合并切片
- 利用\[:]的方式制造切片
- 截取示范
- 截取的地址分析
- := 賦值的影響
- range 的使用
- copy的使用
- Map映射
- 基本示例
- map在并發讀寫中的問題
- Map原理
- map 結構
stirng 字符串
- 求長度還是utf庫中求,因為中文有占3/4字節的,用len不準確
- 符串和數組不能直接123 + “456”這樣拼接
con := fmt.Sprintf("123%d",456)println(con)
區分 rune,byte,string
package mainimport ("fmt"
)func main() {s := "hello world" //直接字符串形式for _, v := range s {fmt.Printf("value is %c,type is %T\n", v, v)//typeis:int32value (rune)}for _, v := range s {fmt.Println(v) //是 int32 形式的數字//is int32vlaue (rune)fmt.Println(string(v))//string}tokens := []string{"2", "1", "+", "3", "*"} //用 string處理for i := 0; i < len(tokens); i++ {fmt.Printf("type is %T\n", tokens[i])//type is string}bytes := []byte("hello world") //用 byte 處理for i := 0; i < len(bytes); i++ {fmt.Printf("value is %c,type is %T", bytes[i], bytes[i])//type is uint8fmt.Println(bytes[i])//value is 104,type is uint8}runes := []rune(s)for i := 0; i < len(runes); i++ {fmt.Printf("value is %c,type is %T\n", runes[i], runes[i])//value is h,type is runefmt.Println(string(runes[i]))//string}
}
總結:
- 原始字符串之中 的內容每一個是 rune 存儲,rune 是 int32
- byte 就是轉為 int8
- string類型是不同于 rune 的,stirng 的列表中的類型就是 string 而不是 rune 的 int32
字符串操作
strings 庫相關
常用:
func main() {fmt.Println(strings.ToUpper("hello"))fmt.Println(strings.ToLower("HELLO"))fmt.Println(strings.Replace("hello world", "world", "go", -1)) //hello gofmt.Println(strings.Split("hel-lo-w-rld", "-")) //[hel lo w rld]fmt.Println(strings.Join([]string{"hel", "lo", "w", "rld"}, "-")) //hel-lo-w-rld
}
fmt.Printf語法
//輸出形式
fmt.Printf("整數:%d\n", 123) // %d:十進制整數
fmt.Printf("字符:%c\n", 'A') // %c:字符
fmt.Printf("字符串:%s\n", "hello") // %s:字符串
fmt.Printf("布爾值:%t\n", true) // %t:布爾值
fmt.Printf("浮點數:%f\n", 3.14) // %f:浮點數
fmt.Printf("二進制:%b\n", 15) // %b:二進制
fmt.Printf("十六進制:%x\n", 15) // %x:十六進制(小寫) //類型相關
fmt.Printf("類型:%T\n", 123) // %T:類型
fmt.Printf("值:%v\n", 123) // %v:默認格式
fmt.Printf("Go語法:%#v\n", "hello") // %#v:Go語法格式
fmt.Printf("p=%+v\n", p) // p={x:1 y:2} 打印結構體字段和名
fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2} 打印更具體結構體名稱
Println 會自動回車,Printf 需要\n
Slice 切片
切片:定義,切片長度(實際大小len),容量(底層數組大小cap) 三個組成
基礎知識
- []中有數字就是數組,沒有就是切片! (牢記)
- []int{1,2,3}就是切片
- 通常利用make()進行創建 如果使用{}就是直接書寫數組內容
- []中不可以是變量比如 k ,后面這樣可以:[…] int {1,2,3,4} / [5] int {1,2,3,4,5}
- make 初始化的時候如果只指定一個參數,那么就是切片長度=容量 這樣初始化 注意只要是初始化的,都會用 0 占位!!
- 理解res := []int{} 或者 var res []int 或者 res := make([]int,0) 不同的創建方式,經常還是用 make 更加直觀
數組和切片的區別
array:數組 (不過變量命名無所謂) slice:切片
![[…/…/attachments/Pasted image 20250525104949.png]]
基本用的都是切片
append函數
通過append看切片和擴容
- 不能直接使用索引來突破切片的長度限制
func main() {a := make([]int, 5, 10) //長度a = append(a, 1, 2, 3,4)fmt.Printf("追加后切片長度為:%d,容量為:%d\n", len(a), cap(a))fmt.Println(a[0:5])fmt.Printf("追加后賦值的切片長度為:%d,容量為:%d\n", len(s1), cap(s1))fmt.Printf("追加后原來的切片長度為:%d,容量為:%d\n", len(a), cap(a))
}
//追加后切片長度為:9,容量為:10
//[0 0 0 0 0]
//追加后賦值的切片長度為:12,容量為:20
//追加后原來的切片長度為:9,容量為:10
通過 append 合并切片
func main() {array := []int{1, 2, 3, 4, 5}array2 := []int{1, 2, 3, 4, 5}res := append(array,array2...) //需要加...fmt.Println(res)//[1 2 3 4 5 1 2 3 4 5]
}
算法中常用:
a := int(len(numbers)/2) //取出中間元素的位置
nunbers = append(numbers[:a],numbers[a+1:]...) //去掉這個個數
利用[:]的方式制造切片
截取示范
- :后面的是不包括在里面的
func main() {array := []int{1, 2, 3, 4, 5}s1 := array[:3]s2 := array[:]fmt.Println(s1, s2) // [1 2 3] [1 2 3 4 5] }
截取的地址分析
- 二者地址上就差8個字節
func main() {array := []int{1, 2, 3, 4, 5}s1 := array[1:]fmt.Printf("array 切片地址%p\n",array) //不是 array 這個變量的地址,做好區分fmt.Printf("s1 切片地址%p\n",s1)fmt.Printf("array 變量地址%p\n",&array) //和上面切片地址是不一樣的
}
:= 賦值的影響
賦值的操作本質上就是參數拷貝
利用:=來共享底層數組的切片,修改時會同時影響到
func main() {array := []int{1, 2, 3, 4, 5}s1 := arrays2 := array[1:3]array[0] = 100fmt.Println(s1)fmt.Println(s2)//[100 2 3 4 5]//[2 3]
}
range 的使用
func main() {nums := []int{2, 3, 4}sum := 0for _, num := range nums {sum += num}fmt.Println("sum:", sum)for i, num := range nums {if num == 3 {fmt.Println("index:", i)}//index: 1 }kvs := map[string]string{"a": "apple", "b": "banana"}for k, v := range kvs {fmt.Printf("%s -> %s\n", k, v)}//兩個變量的時候傳遞的是key - valuefor k := range kvs {fmt.Println("key:", k)}//只有一個的時候,傳遞的是 keyfor i, c := range "go" {fmt.Println(i, c)}//0 103// 1 111 本質因為字符串之中是 int32 存儲的}#### slice 相關庫
###### slices.Equal(a,b) return bool 判斷是否相等
```Go
func main() {array := []int{1, 2, 3, 4, 5}s1 := arrayres:=slices.Equal(s1, array)fmt.Println(res) // Output: true
}
比較的時候不會看切片的 cap 是不是一樣的,就是看 len 中的
copy的使用
有多少就 copy 多少,(,)從后面的 copy 到前面的
func main() {array := []int{1, 2, 3, 4, 5}s1 := make([]int, 6)s2:= make([]int, len(array))s3 := make([]int, 3)fmt.Println(len(s1), cap(s1)) // Output: 6,6copy(s1, array)copy(s2, array)copy(s3, array)fmt.Println(s1) // Output: [1 2 3 4 5 0]fmt.Println(s2) // Output: [1 2 3 4 5]fmt.Println(s3) // Output: [1 2 3]res := slices.Equal(s1, array)res2 := slices.Equal(s2, array)fmt.Println(res) // Output: falsefmt.Println(res2) // Output: true
}
Map映射
類似于 python 的字典
- key和value 鍵-值的對應
- var mapname map[keytype] valuetype 定義
基本示例
func main() {m := make(map[string]int)//map will auto increasem["k1"] = 7m["k2"] = 13fmt.Println("map:", m)v1 := m["k1"]fmt.Println("v1:", v1)v3 := m["k3"]fmt.Println("v3:", v3)fmt.Println("len:", len(m))delete(m, "k2")fmt.Println("map:", m)//delete certain keyclear(m)fmt.Println("map:", m)//clear all of the map_, prs := m["k2"]fmt.Println("prs:", prs)//return the value and indication about the key's existence//to disambiguate between missing keys and keys with zero values like 0 n := map[string]int{"foo": 1, "bar": 2}fmt.Println("map:", n)n2 := map[string]int{"foo": 1, "bar": 2}if maps.Equal(n, n2) {fmt.Println("n == n2")}
}
map在并發讀寫中的問題
aa := make(map[int]int)go func ( for {// aa[0] = 5 //不可以的,不支持并發寫_ = aa[2] //可以的,讀操作不影響寫操作})()go func () {for {_ = aa[1]}}()
Map原理
map 結構
指定map長度為N,會初始化生成桶,桶數量為log2N
map在超過負載因子的時候會雙倍重建,如果溢桶太大就會等量重建。當用到的時候舊桶才會放入新桶