2. 內建容器
阿新 • • 發佈:2018-12-01
一. 陣列
陣列是值型別
- [10]int 和 [20]int 是不同的型別
- 呼叫func f(arr [10]int) 會拷貝 陣列
- go語言中其實一般不直接使用陣列, 而是使用切片
package main import "fmt" func printArray(arr [5]int) { // [5]是值型別 []是一個切片, 兩者有很大區別 arr[0] = 100 // 因為是值型別, 所以arr[0] 實際上沒有變為100, 只在函式內部變為100 for i, v := range arr { // range 關鍵字 可以獲取 index 和value fmt.Println(i, v) } } func main() { // 陣列有多種定義方法 var arr1 [5]int arr2 := [3]int{1, 3, 5} // := 需要給初值 arr3 := [...]int{2, 4, 6, 8, 10} // [...] 自動根據後面的 元素個數 確定陣列的容量 var grid [4][5]int // 二維陣列 fmt.Println("array definitions:") fmt.Println(arr1, arr2, arr3) fmt.Println(grid) // 未賦值的元素 預設為0 fmt.Println("printArray(arr1)") printArray(arr1) fmt.Println("printArray(arr3)") printArray(arr3) fmt.Println("arr1 and arr3") fmt.Println(arr1, arr3) //arr[0] 實際上沒有變為100 }
二. Slice (切片)
常用用法
package main import "fmt" func updateSlice(s []int) { //[] 裡沒有數字 就是個slice 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) /* 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] */ fmt.Println("After updateSlice(s1)") updateSlice(s1) fmt.Println(s1) fmt.Println(arr) /* After updateSlice(s1) [100 3 4 5 6 7] [0 1 100 3 4 5 6 7] */ fmt.Println("After updateSlice(s2)") updateSlice(s2) fmt.Println(s2) fmt.Println(arr) /* After updateSlice(s2) [100 1 100 3 4 5 6 7] [100 1 100 3 4 5 6 7] */ fmt.Println("Reslice") fmt.Println(s2) s2 = s2[:5] fmt.Println(s2) s2 = s2[2:] fmt.Println(s2) /* Reslice [100 1 100 3 4 5 6 7] [100 1 100 3 4] [100 3 4] */ }
slice的擴充套件
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6] # 得到[2 3 4 5]
s2 := s1[3:5] # 得到[5 6]
- slice可以想後擴充套件, 不可以向前擴充套件
- s[i] 不可以超越 len(s), 向後擴充套件不可以超越底層陣列cap(s)
package main
func main() {
fmt.Println("Extending slice")
arr[0], arr[2] = 0, 2
fmt.Println("arr =", arr)
s1 = arr[2:6]
s2 = s1[3:5] // [s1[3], s1[4]]
fmt.Printf("s1=%v, len(s1)=%d, cap(s1)=%d\n",
s1, len(s1), cap(s1))
fmt.Printf("s2=%v, len(s2)=%d, cap(s2)=%d\n",
s2, len(s2), cap(s2))
/*
Extending slice
arr = [0 1 2 3 4 5 6 7]
s1=[2 3 4 5], len(s1)=4, cap(s1)=6
s2=[5 6], len(s2)=2, cap(s2)=3 // 可以看到 6並不在s1中, 但s2依然可以獲取
// 但是 s1[4] 會報錯, 即下角標無法索引 cap, 只有slice 可以
*/
}
向Slice新增元素
- cap的長度不會變, 但值是可以被改變的
- 新增元素如果超越cap, 系統就會重新分配更大的底層陣列
s3 := append(s2, 10)
s4 := append(s3, 11)
s5 := append(s4, 12)
fmt.Println("s3, s4, s5 =", s3, s4, s5)
// s4 and s5 no longer view arr.
fmt.Println("arr =", arr)
/*
s3, s4, s5 = [5 6 10] [5 6 10 11] [5 6 10 11 12]
arr = [0 1 2 3 4 5 6 10]
s3改變了cap的最後一個元素
s4 s5 超越了cap
s4 和 s5 的cap就不是arr了
*/
slice的操作
- create slice
- copy slice
- Deleting elements from slice
- Popping from front
- Popping from back
package main
import "fmt"
func printSlice(s []int) {
fmt.Printf("%v, len=%d, cap=%d\n",
s, len(s), cap(s))
}
func sliceOps() {
fmt.Println("Creating slice")
var s []int // Zero value for slice is nil
for i := 0; i < 100; i++ {
printSlice(s) // cap 每次裝不下了, 就*2 0 1 2 4 8 16 32 64....
s = append(s, 2*i+1)
}
fmt.Println(s)
s1 := []int{2, 4, 6, 8}
printSlice(s1)
s2 := make([]int, 16) // make 建立 16 長度的slice 但內容不知道
s3 := make([]int, 10, 32) // cap設定為32
printSlice(s2)
printSlice(s3)
fmt.Println("Copying slice")
copy(s2, s1)
printSlice(s2) //[2 4 6 8 0 0 0 0 0 0 0 0 0 0 0 0], len=16, cap=16
fmt.Println("Deleting elements from slice")
s2 = append(s2[:3], s2[4:]...) // 刪除下標為3 s2[4:]... 表示 拆解s2[4:] 變成一個一個單獨引數 傳入
printSlice(s2) //[2 4 6 0 0 0 0 0 0 0 0 0 0 0 0], len=15, cap=16
fmt.Println("Popping from front")
front := s2[0]
s2 = s2[1:]
fmt.Println(front) //2
printSlice(s2) //[4 6 0 0 0 0 0 0 0 0 0 0 0 0], len=14, cap=15
fmt.Println("Popping from back")
tail := s2[len(s2)-1]
s2 = s2[:len(s2)-1]
fmt.Println(tail) //0
printSlice(s2) //[4 6 0 0 0 0 0 0 0 0 0 0 0], len=13, cap=15
}
func main() {
sliceOps()
}
三. Map
使用
- 類似python的dict
package main
import "fmt"
func main() {
// 三種建立方法--------------------------------------------------
m := map[string]string{
"name": "ccmouse",
"course": "golang",
"site": "imooc",
"quality": "notbad",
}
m2 := make(map[string]int) // m2 == empty map
var m3 map[string]int // m3 == nil
fmt.Println("m, m2, m3:")
fmt.Println(m, m2, m3) //map[name:ccmouse course:golang site:imooc quality:notbad] map[] map[]
// 遍歷方法--------------------------------------------------
fmt.Println("Traversing map m")
for k, v := range m {
fmt.Println(k, v)
}
/*
quality notbad
name ccmouse
course golang
site imooc
Getting values
*/
// 獲取元素--------------------------------------------------
fmt.Println("Getting values")
courseName := m["course"]
fmt.Println(`m["course"] =`, courseName) // m["course"] = golang
// 判斷map中key 是否存在--------------------------------------------------
if causeName, ok := m["cause"]; ok { // 沒有cause這個key ok是false的
fmt.Println(causeName)
} else {
fmt.Println("key 'cause' does not exist")
}
// 刪除元素--------------------------------------------------
fmt.Println("Deleting values")
name, ok := m["name"]
fmt.Printf("m[%q] before delete: %q, %v\n",
"name", name, ok) //["name"] before delete: "ccmouse", true
delete(m, "name") // 刪除
name, ok = m["name"]
fmt.Printf("m[%q] after delete: %q, %v\n",
"name", name, ok) //m["name"] after delete: "", false
}
map的key
- map使用雜湊表, 必須可以比較是否相等
- 除了slice, map, function的 內建型別都可以作為key
- Struct型別不包含2中型別的欄位, 也可以作為key
map使用的例子
leetcode第3題
給定一個字串,找出不含有重複字元的最長子串的長度。
示例 1:
輸入: "abcabcbb"
輸出: 3
解釋: 無重複字元的最長子串是 "abc",其長度為 3。
示例 2:
輸入: "bbbbb"
輸出: 1
解釋: 無重複字元的最長子串是 "b",其長度為 1。
示例 3:
輸入: "pwwkew"
輸出: 3
解釋: 無重複字元的最長子串是 "wke",其長度為 3。
請注意,答案必須是一個子串,"pwke" 是一個子序列 而不是子串。
- 解題
package main
import (
"fmt"
)
func lengthOfNonRepeatingSubStr(s string) int {
lastOccurred := make(map[rune]int)
start := 0
maxLength := 0
for i, ch := range []rune(s) {
if lastI, ok := lastOccurred[ch]; ok && lastI >= start {
start = lastI + 1
}
if i-start+1 > maxLength {
maxLength = i - start + 1
}
lastOccurred[ch] = i
}
return maxLength
}
func main() {
fmt.Println(
lengthOfNonRepeatingSubStr("abcabcbb"))
fmt.Println(
lengthOfNonRepeatingSubStr("bbbbb"))
fmt.Println(
lengthOfNonRepeatingSubStr("pwwkew"))
fmt.Println(
lengthOfNonRepeatingSubStr(""))
fmt.Println(
lengthOfNonRepeatingSubStr("b"))
fmt.Println(
lengthOfNonRepeatingSubStr("abcdef"))
fmt.Println(
lengthOfNonRepeatingSubStr("這裡是慕課網"))
fmt.Println(
lengthOfNonRepeatingSubStr("一二三二一"))
fmt.Println(
lengthOfNonRepeatingSubStr(
"黑化肥揮發發灰會花飛灰化肥揮發發黑會飛花"))
}
/*
3
1
3
0
1
6
6
3
8
*/
字元和字串
- rune uint32
- byte uint8
- 使用range 遍歷pos,rune對
- 使用utf8.RuneCountInString獲得字元數量
- 使用len獲取位元組長度
- 使用[]byte獲得位元組
- 使用[]rune獲得字元
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
s := "Yes我愛慕課網!" // UTF-8
fmt.Println(s)
for _, b := range []byte(s) { //byte uint8
fmt.Printf("%X ", b) //59 65 73 E6 88 91 E7 88 B1 E6 85 95 E8 AF BE E7 BD 91 21
}
fmt.Println()
for i, ch := range s { // ch is a rune 即uint32 s是utf8的, 而ch是uint32 所以得到如下結果
fmt.Printf("(%d %X) ", i, ch) //(0 59) (1 65) (2 73) (3 6211) (6 7231) (9 6155) (12 8BFE) (15 7F51) (18 21) 索引是不連續的
}
fmt.Println()
fmt.Println("Rune count:",
utf8.RuneCountInString(s)) //獲取字元數量 Rune count: 9
bytes := []byte(s)
for len(bytes) > 0 {
ch, size := utf8.DecodeRune(bytes)
bytes = bytes[size:]
fmt.Printf("%c ", ch) //Y e s 我 愛 慕 課 網 !
}
fmt.Println()
for i, ch := range []rune(s) { // rune(s)轉化
fmt.Printf("(%d %c) ", i, ch) //(0 Y) (1 e) (2 s) (3 我) (4 愛) (5 慕) (6 課) (7 網) (8 !)
}
fmt.Println()
}