數(shù)組
定義
var
, :=
關(guān)鍵字; 元素?cái)?shù)量寫在類型前面
var arr1 [5] int // 中括號(hào)數(shù)字, 是指定元素個(gè)數(shù), 默認(rèn)元素為 0
arr2 := [3] int {1, 2, 3}
arr3 := [...] int {4, 5, 6, 7, 8} // 讓編譯器計(jì)算元素個(gè)數(shù)
var grid [4][5] int // 代表 4 行 5 列 二維數(shù)組, 只能用 var 聲明
遍歷
// 方式一
arr3 := [...] int {1, 3, 5, 7, 9}
for i := 0; i < len(arr3); i++ {
fmt.println(arr3[i])
}
// 方式二
for i := range arr3 {
fmt.Println(arr3[i])
}
// 方式三, 輸出 i, v
for i, v := range arr3 {
fmt.println(i, v)
}
// 只輸出 v, 使用 "_" 替換 i
for _, v := range arr3 {
fmt.println(v)
}
類型
-
數(shù)組是值類型
package main import "fmt" func printArray(arr [5]int) { // 若此處將數(shù)組下標(biāo)為 0 的元素,會(huì)重新賦值成100 arr[0] = 100 for i, v := range arr { fmt.Println(i, v) } } func main() { var arr1 [5] int // 中括號(hào)數(shù)字, 是指定元素個(gè)數(shù), 默認(rèn)元素為 0 arr2 := [3] int {1, 2, 3} arr3 := [...] int {4, 5, 6, 7, 8} // 讓編譯器計(jì)算元素個(gè)數(shù) var grid [4][5] int // 二維數(shù)組, 只能用 var 聲明 fmt.Println(arr1, arr2, arr3) // 這里輸出的數(shù)組還是原來的數(shù)組, 沒有改變 fmt.Println(grid) printArray(arr3) }
小結(jié)
-
[10] int
和[20] int
是不同的類型 - 調(diào)用
func f(arr [10] int)
會(huì)重新 拷貝 一個(gè)數(shù)組 -
Go
語言中一般不直接使用數(shù)組
切片 slice
概念
Go 語言切片是對(duì)數(shù)組的抽象醇份°擦椋可以理解成數(shù)組的 view
Go 數(shù)組的長度不可改變领炫,在特定場(chǎng)景中這樣的集合就不太適用饵蒂,Go 中提供了一種靈活辛辨,功能強(qiáng)悍的內(nèi)置類型切片("動(dòng)態(tài)數(shù)組"),與數(shù)組相比切片的長度是不固定的拷邢,可以追加元素香府,在追加時(shí)可能使切片的容量增大。
操作
基操
package main
import "fmt"
// slice 不是值傳遞,可以看成 視圖
func updateSlice(s []int) {
s[0] = 100
}
func main() {
arr := [...] int {0, 1, 2, 3, 4, 5, 6, 7}
fmt.Println("arr[2:6] = ", arr[2:6])
fmt.Println("arr[:6] = ", arr[:6])
s1 := arr[2:]
fmt.Println("s1 = ", s1)
s2 := arr[:]
fmt.Println("s2 = ", s2)
fmt.Println("After updateSlice(s1)")
updateSlice(s1)
fmt.Println(s1)
fmt.Println(arr)
fmt.Println("After updateSlice(s2)")
updateSlice(s2)
fmt.Println(s2)
fmt.Println(arr)
fmt.Println("Reslice")
fmt.Println(s2)
s2 = s2[:5]
fmt.Println(s2)
s2 = s2[2:]
fmt.Println(s2)
}
// 結(jié)果
arr[2:6] = [2 3 4 5]
arr[:6] = [0 1 2 3 4 5]
s1 = [2 3 4 5 6 7]
s2 = [0 1 2 3 4 5 6 7]
After updateSlice(s1)
[100 3 4 5 6 7]
[0 1 100 3 4 5 6 7]
After updateSlice(s2)
[100 1 100 3 4 5 6 7]
[100 1 100 3 4 5 6 7]
Reslice
[100 1 100 3 4 5 6 7]
[100 1 100 3 4]
[100 3 4]
擴(kuò)展
arr := [...] int {0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
s2 := s1[3:5]
問 :
s1 的值?
-
s2 的值?
s1 的值 [2 3 4 5] s2 的值 [5 6]
答 :
s1
從 arr
中取得新數(shù)組 [2, 3, 4, 5]
, 那么 s1
的下標(biāo)分別是 0, 1, 2, 3
; 由于s1
是 arr
的 view, s1
和 arr
存在映射關(guān)系. arr
中的元素 6, 7
對(duì)應(yīng)著 s1
不可見下標(biāo) 4, 5
; s2
獲取 s1
的 3,5
等同于獲取 arr
中的 5, 7
; 左開右閉 原則, 所以 s2
的值就是 [5, 6]
- 知識(shí)點(diǎn)

- `slice` 可以向后擴(kuò)展, 不可以向前擴(kuò)展
- `s[i]` 不可以超越 `len(s)`, 向后擴(kuò)展不可以超越底層數(shù)組 `cap(s)`
添加元素
arr := [...] int {0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
s2 := s1[3:5]
s3 := append(s2, 10)
s4 := append(s3, 11)
s5 := append(s4, 12)
問 : s3, s4, s5 的值為多少? arr的值又變成
結(jié)果 :
[2 3 4 5]
[5 6]
[5 6 10]
[5 6 10 11]
[5 6 10 11 12]
- 關(guān)鍵字
append
- 添加元素時(shí)如果超越
cap
, 系統(tǒng)會(huì)重新分配更大的底層數(shù)組 - 由于值傳遞關(guān)系, 必須接收
append
的返回值 s = append(s, val)
復(fù)雜操作
-
追加
append(s, v)
第一個(gè)參數(shù)是追加的slice
, 第二個(gè)是element
func main () { var s [] int // 空的 slice, 默認(rèn) 0 填充 for i := 0; i < 100; i++ { s = append (s, 2 * i + 1) } }
-
設(shè)置指定長度的
slice
make([]int, 16, 32)
第一個(gè)參數(shù)創(chuàng)建類型, 第二個(gè)參數(shù)是長度, 第三個(gè)是分配的空間(可選)// 建立長度為 16 的 slice s2 := make([]int, 16) s3 := make([]int, 10, 32)
-
復(fù)制
slice
copy(s1, s2)
第一個(gè)參數(shù)是要復(fù)制的目標(biāo)slice
恼策,第二個(gè)參數(shù)是源slice
s1 := [] int {2, 3, 4, 5} s2 := make([]int, 16) copy(s2, s1) // 結(jié)果 [2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0], len = 16, cap = 16
-
刪除一個(gè)元素
沒有刪除函數(shù), 采取截取, 再拼接的方式實(shí)現(xiàn)刪除
s2 = append(s2[:3] , s2[4:]...) // 結(jié)果 [2 3 4 0 0 0 0 0 0 0 0 0 0 0 0], len = 15, cap = 16
-
頭部 Pop 一個(gè)元素
同樣, 也是采取截取的方式
s2 = s2[1:] // 結(jié)果 [3 4 0 0 0 0 0 0 0 0 0 0 0 0], len = 14, cap = 15
-
尾部 Pop 一個(gè)元素
同樣, 也是采取截取的方式
s2 = s2[:len(s2) - 1] // 結(jié)果 [3 4 0 0 0 0 0 0 0 0 0 0 0], len = 13, cap = 15
Map
定義
關(guān)鍵字 map[k]v
格式 :
map[K]V, map[K1]map[K2]V
示例
創(chuàng)建
// 示例 一
m := map[string] string {
"name" : "mouse",
"course" : "golang",
"site" : "imooc"
}
// 示例 二
m2 := make(map[string]int) // m2 == empty mpa
// 示例 三
var m3 map[string]int // m3 == nil
應(yīng)用
-
循環(huán)輸出
// 循環(huán)輸出 map for k, v := range m { fmt.println(k, v) } // 結(jié)果, 可以出來 map 的 k 是無序的 site imooc quality good name mouse course golang Getting values
-
獲取其中一個(gè)值
// 獲取 map 其中一個(gè)值 courseName, ok := m["course"] fmt.println(courseName, ok) // 結(jié)果 golang true
-
若
k
不存在// 若獲取的 k 不存在, 則返回 空 causeName, ok2 := m["cause"] fmt.println(causeName, ok2) // 結(jié)果 "" false // 改寫 if causeName, ok2 := m["cause"]; ok { fmt.println(causeName) } else { fmt.println("key does no exist") } // 結(jié)果 key does not exist
-
刪除一個(gè)值
delete()
, 第一個(gè)參數(shù)是map
, 第二個(gè)參數(shù)是要?jiǎng)h除的key
name, ok := m["name"] fmt.println(name, ok) delete(m, "name") // 結(jié)果 map[course:golang quality:good site:imooc]
小結(jié)
- 創(chuàng)建:
make(map[string]int)
- 獲取元素 :
map[key]
- 若
key
不存在時(shí), 則取得Value
類型的初始值, 不會(huì)報(bào)錯(cuò) - 使用
value, ok := m[key]
兩個(gè)值來判斷key
是否存在 - 使用
delete(m, key)
刪除一個(gè)值 - 使用
range
遍歷key
, 或者遍歷key
,value
對(duì) - 不能保證遍歷順序, 若需要順序, 可以添加到
slice
再對(duì)slice
排序 - 使用
len
獲得元素個(gè)數(shù) -
map
使用哈希表, 必須可以比較相等 - 除了
slice
,map
,func
的內(nèi)建類型都可以作為key
-
strut
類型不包含上述字段, 也可以作為key
高級(jí)操作
例子 一
尋找最長不含有重復(fù)字符的子串
abcabcbb ---> abc
bbbbb ---> b
pwwkew ---> wke
對(duì)于每一個(gè)字母
x
lastOccurred[x] 不存在, 或者 < start, 無需操作
lastOccurred[x] >= start, 則更新 start
-
更新 lastOccurred[x], 更新 maxLength
func lengthOfNonRepeatingSubStr(s string) int { lastOccurred := make(map[byte]int) start := 0 maxLength := 0 for i, ch := range []byte(s){ lastI, ok := lastOccurred[ch] if ok && lastI >= start { start = lastI + 1 } if i - start + 1 > maxLength { maxLength = i - start + 1 } lastOccurred[ch] = i } return maxLength }
計(jì)算中文等漢字會(huì)出現(xiàn)問題
字符和字符串處理
rune
相當(dāng)于 Go 的 char
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
s := "Yes中文!"
fmt.println(s) // 輸出結(jié)果: 10
for _, b := range []byte(s) {
fmt.printf("%X ", b) // 輸出十六進(jìn)制
}
}
// 引入 unicode/utf8 包
fmt.Println("Rune count", utf8.RuneCountInString(s)) // 輸出6
bytes := []byte(s)
for len(bytes) > 0 {
ch, size := utf8.DecodeRune(bytes)
bytes = bytes[size:]
fmt.printf("%c ", ch) // 輸出 Y e s 中 文 !
}
// 使用 rune, 可直接輸出漢字
for i, ch := range []rune(s) {
fmt.printf("(%d, %c)", i, ch) // 輸出 (0, Y)(1, e)(2, s)(3, 中)(4, 文)(5, !)
}
再對(duì)上面的例子 一, 遺留的問題進(jìn)行修改
func lengthOfNonRepeatingSubStr(s string) int {
// 將 byte 修改成 rune 即可解決
lastOccurred := make(map[rune]int)
start := 0
maxLength := 0
// 將 byte 修改成 rune 即可解決
for i, ch := range []rune(s){
lastI, ok := lastOccurred[ch]
if ok && lastI >= start {
start = lastI + 1
}
if i - start + 1 > maxLength {
maxLength = i - start + 1
}
lastOccurred[ch] = i
}
return maxLength
}
-
其他字符操作
推薦使用
strings
package 來處理, 里面有很多函數(shù), 多多嘗試就會(huì)用了