Go 第3章 内建容器

2021-06-08

一、数组

  • 数量写在类型前面

package main
import (
    "fmt"
)
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(arr1, arr2, arr3, grid)
}
  • 数组的遍历

    • 可通过_省略变量

    • 不仅 range,任何地方都可通过_省略变量

    • 如果只要 i,可写成 for i := range numbers

package main
import (
    "fmt"
)
func main() {
    arr := [...] int {2, 4, 6, 8, 10}
    for i := 0; i < len(arr); i++ {
        fmt.Println(arr[i])
    }
    for i, v := range arr {
        fmt.Println(i, v)
    }
    for _, v := range arr {
        fmt.Println(v)
    }
}
  • 数组是值类型

    • [10]int 和 [20]int 是不同类型

    • 调用 func f(arr [10]int) 会拷贝数组

    • 在 go 语言中一般不直接使用数组

package main
import (
    "fmt"
)
func main() {
    var arr1 [5]int
    arr2 := [...]int{2, 4, 6, 8, 10}
    fmt.Println("printArray(arr1)")
    printArray(arr1)
    fmt.Println("printArray(arr2)")
    printArray(arr2)
    fmt.Println("arr1 and arr2")
    fmt.Println(arr1, arr2)
}
func printArray(arr [5]int) {
    arr[0] = 100
    for i, v := range arr {
fmt.Println(i, v)
    }
}

二、切片 slice

2.1、切片的概念

  • slice 本身没有数据,是对底层 array 的一个 view

package main
import "fmt"
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)
}
  • slice 扩展

package main
import "fmt"
func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    fmt.Println("arr =", arr)
    s1 := arr[2:6]
    s2 := s1[3:5]
    fmt.Println("s1 =", s1)
    fmt.Println("s2 =", s2)
}

https://file.lulublog.cn/images/3/2022/08/Nf9ThBgHv9N4hQFbghFgZ90g4ZKc4k.png

  • slice 的实现如下图

  • slice 可以向后扩展,不可以向前扩展

  • s[i] 不可以超越 len(s),向后扩展不可以超越底层数组 cap(s):cap=capacity容量

https://file.lulublog.cn/images/3/2022/08/f009c2cC6XaZex004Eh5eP5oXCC9H5.png

package main
import "fmt"
func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    fmt.Println("arr =", arr)
    s1 := arr[2:6]
    s2 := s1[3:5]
    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))
}

2.2、切片的操作

  • 向 slice 添加元素:append(s, val)

    • 添加元素时如果超越 cap,系统会重新分配更大的底层数组

    • 由于值传递的关系,必须接收 append 的返回值

package main
import "fmt"
func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    fmt.Println("arr =", arr)
    s1 := arr[2:6]
    s2 := s1[3:5]
    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)
}
  • 创建 slice:make 函数

package main
import "fmt"
func main() {
    var s []int // Zero value for slice is nil
    for i := 0; i < 100; i++ {
printSlice(s)
s = append(s, 2*i+1)
    }
    fmt.Println(s)
    s1 := []int{2, 4, 6, 8}
    printSlice(s1)
    s2 := make([]int, 12)
    s3 := make([]int, 10, 32)
    printSlice(s2)
    printSlice(s3)
}
func printSlice(s []int) {
    fmt.Printf("%v, len=%d, cap=%d\n",
s, len(s), cap(s))
}
  • 复制 slice:copy 函数

package main
import "fmt"
func main() {
    s1 := []int{2, 4, 6, 8}
    printSlice(s1)
    s2 := make([]int, 12)
    printSlice(s2)
    copy(s2, s1)
    printSlice(s2)
}
func printSlice(s []int) {
    fmt.Printf("%v, len=%d, cap=%d\n",
        s, len(s), cap(s))
}
  • 删除 slice:删除第二个元素

package main
import "fmt"
func main() {
    s1 := []int{2, 4, 6, 8}
    printSlice(s1)
    s1 = append(s1[:1], s1[2:]...)
    printSlice(s1)
}
func printSlice(s []int) {
    fmt.Printf("%v, len=%d, cap=%d\n",
s, len(s), cap(s))
}
  • 删除 slice:删除头部、删除尾部

package main
import "fmt"
func main() {
   s1 := []int{2, 4, 6, 8}
   printSlice(s1)
   fmt.Println("Popping from front")
   front := s1[0]
   s1 = s1[1:]
   fmt.Println(front)
   printSlice(s1)
   fmt.Println("Popping from back")
   tail := s1[len(s1)-1]
   s1 = s1[:len(s1)-1]
   fmt.Println(tail)
   printSlice(s1)
}
func printSlice(s []int) {
   fmt.Printf("%v, len=%d, cap=%d\n",
s, len(s), cap(s))
}

三、Map

3.1、创建

package main
import "fmt"
func main() {
    m1 := map[string]string{
"name": "lulubin",
"course": "golang",
"site": "lulublog",
"quality": "notbad",
    }
    m2 := make(map[string]int) // m2 == empty map
    var m3 map[string]int // m3 == nil
    fmt.Println("m1=", m1);
    fmt.Println("m2=", m2);
    fmt.Println("m3=", m3);
}

3.2、获取

  • key 不存在时,获得 value 类型的初始值

  • 用 value, ok:= m[key] 来判断是否存在 key

package main
import "fmt"
func main() {
    m := map[string]string{
"name": "lulubin",
"course": "golang",
"site": "lulublog",
"quality": "notbad",
    }
    courseName := m["course"]
    fmt.Println(`m["course"] =`, courseName)
    if causeName, ok := m["cause"]; ok {
fmt.Println(causeName)
    } else {
fmt.Println("key 'cause' does not exist")
    }
}

3.3、删除

package main
import "fmt"
func main() {
    m := map[string]string{
"name": "lulubin",
"course": "golang",
"site": "lulublog",
"quality": "notbad",
    }
    name, ok := m["name"]
    fmt.Printf("m[%q] before delete: %q, %v\n", "name", name, ok)
    delete(m, "name")
    name, ok = m["name"]
    fmt.Printf("m[%q] after delete: %q, %v\n", "name", name, ok)
}

3.4、遍历

  • 使用 range 遍历 key,或者遍历 key, value 对

  • 不保证遍历顺序,如需顺序,需手动对 key 排序

  • 使用 len 获得元素个数

package main
import "fmt"
func main() {
    m := map[string]string{
"name": "lulubin",
"course": "golang",
"site": "lulublog",
"quality": "notbad",
    }
    for k, v := range m {
fmt.Println(k, v)
    }
}

3.5、map 的 key

  • map 使用哈希表,必须可以比较相等

  • 除了 slice, map, function 的内建类型都可以作为 key

  • Struct 类型不包含上述字段,也可作为 key

3.6、例题

3.6.1、题目

寻找最长不含有重复字符的子串

  • 示例 1:

    • 输入:s = "abcabcbb"

    • 输出:3

    • 解释:因为无重复字符的最长子串是 "abc",所以其长度为 3

  • 示例 2:

    • 输入:s = "bbbbb"

    • 输出:1

    • 解释:因为无重复字符的最长子串是 "b",所以其长度为 1

  • 示例 3:

    • 输入:s = "pwwkew"

    • 输出:3

    • 解释:因为无重复字符的最长子串是 "wke",所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

  • 示例 4:

    • 输入:s = ""

    • 输出:0

3.6.2、解题思路

  • 对于每一个字母 x

  • lastOccurred[x] 不存在,或者< start →无需操作

  • lastOccurred[x] >= start >更新start

  • 更新 lastOccurred[x],更新 maxLength

3.6.3、代码

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("黑化肥挥发发灰会花飞灰化肥挥发发黑会飞花"))
}

四、字符和字符串处理

4.1、rune

  • rune 相当于 go 的char

  • 使用 range 遍历 pos, rune 对

  • 使用 utf8.RuneCountInString 获得字符数量

  • 使用 len 获得字节长度

  • 使用 []byte 获得字节

4.2、代码

package main
import (
    "fmt"
    "unicode/utf8"
)
func main() {
    s := "Yes我爱鲁鲁博客!" // UTF-8
    fmt.Println(s)
    for _, b := range []byte(s) {
fmt.Printf("%X ", b)
    }
    //59 65 73 E6 88 91 E7 88 B1 E9 B2 81 E9 B2 81 E5 8D 9A E5 AE A2 21
    fmt.Println()
    for i, ch := range s { // ch is a rune
fmt.Printf("(%d %X) ", i, ch)
    }
    //(0 59) (1 65) (2 73) (3 6211) (6 7231) (9 9C81) (12 9C81) (15 535A) (18 5BA2) (21 21)
    fmt.Println()
    fmt.Println("Rune count:",
utf8.RuneCountInString(s))
    //Rune count: 10
    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) {
fmt.Printf("(%d %c) ", i, ch)
    }
    //(0 Y) (1 e) (2 s) (3 我) (4 爱) (5 鲁) (6 鲁) (7 博) (8 客) (9 !)
    fmt.Println()
}

4.3、其他字符串操作

  • Fields、Split、Join

  • Contains、Index

  • ToLower、ToUpper

  • Trim、TrimRight、TrimLeft

阅读 572