切片-学习Go语言

阅读笔记

slices.go

package main

import "fmt"

func main() {
    primes := [6]int{2, 3, 5, 7, 11, 13}

    var s []int = primes[1:4]
    fmt.Println(s)
}

笔记

切片的内部实现,类似一个链表+头尾指针。

数组的切片范围为low<= x < high

slices-pointers.go

package main

import "fmt"

func main() {
    names := [4]string{
        "John",
        "Paul",
        "George",
        "Ringo",
    }
    fmt.Println(names)

    a := names[0:2]
    b := names[1:3]
    fmt.Println(a, b)

    b[0] = "XXX"
    fmt.Println(a, b)
    fmt.Println(names)
}

笔记

切片的数据被引用的。修改切片的数据会直接关联到原来的数组。

slice-literals.go

package main

import "fmt"

func main() {
    q := []int{2, 3, 5, 7, 11, 13}
    fmt.Println(q)

    r := []bool{true, false, true, true, false, true}
    fmt.Println(r)

    s := []struct {
        i int
        b bool
    }{
        {2, true},
        {3, false},
        {5, true},
        {7, true},
        {11, false},
        {13, true},
    }
    fmt.Println(s)
}

笔记

  1. 创建长度为6的int数组,构建一个引用该数组的切片。
  2. 创建长度为6的布尔数组,构建一个引用该数组的切片。
  3. 创建长度为5的结构体数组,构建一个引用该数组的切片。

slice-bounds.go

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}

    s = s[1:4]
    fmt.Println(s)

    s = s[:2]
    fmt.Println(s)

    s = s[1:]
    fmt.Println(s)
}

笔记

  1. 切片的默认值为0到数组长度。
  2. 以数组var a [10]int为例
  3. 切片等价a[0:10] = a[:10] = a[0:] = a[:]

slice-len-cap.go

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    printSlice(s)

    // Slice the slice to give it zero length.
    s = s[:0]
    printSlice(s)

    // Extend its length.
    s = s[:4]
    printSlice(s)

    // Drop its first two values.
    s = s[2:]
    printSlice(s)
}

func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

笔记

  1. 如何理解切片的长度和容量。按照正常逻辑不是只有长度就够了吗?为啥还要新增一个容量呢?
  2. 切片的长度就是它所包含的元素个数。
  3. 切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。
  4. 注意看第二个例子,长度变为0 ,但是容量为什么还是6呢?
  5. 注意第四个例子,是不是起始值变了,才会去修改引用数组的容量?

nil-slices.go

package main

import "fmt"

func main() {
    var s []int
    fmt.Println(s, len(s), cap(s))
    if s == nil {
        fmt.Println("nil!")
    }
}

笔记

  1. 切片的零值是 nil
  2. nil 切片的长度和容量为 0 且没有底层数组。

making-slices.go

package main

import "fmt"

func main() {
    a := make([]int, 5)
    printSlice("a", a)

    b := make([]int, 0, 5)
    printSlice("b", b)

    c := b[:2]
    printSlice("c", c)

    d := c[2:5]
    printSlice("d", d)
}

func printSlice(s string, x []int) {
    fmt.Printf("%s len=%d cap=%d %v\n",
        s, len(x), cap(x), x)
}

笔记

  1. 默认创建len 和cap 相同的切片
  2. a := make([]int, 5) // len(a)=5 cap(a)=5
  3. 注意第四个例子,cap变成了3
  4. 假如d1 := c[3:5],那么cap会变成2
  5. 切片的最大值不能超过原始数组的长度,不然会报错。

slices-of-slice.go

package main

import (
    "fmt"
    "strings"
)

func main() {
    // Create a tic-tac-toe board.
    board := [][]string{
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
    }

    // The players take turns.
    board[0][0] = "X"
    board[2][2] = "O"
    board[1][2] = "X"
    board[1][0] = "O"
    board[0][2] = "X"

    for i := 0; i < len(board); i++ {
        fmt.Printf("%s\n", strings.Join(board[i], " "))
    }
}

笔记

  1. 这尼玛不是就二维数组了吗?
  2. 创建了一个二维数组的切片,也就是切片的切片

append.go

package main

import "fmt"

func main() {
    var s []int
    printSlice(s)

    // append works on nil slices.
    s = append(s, 0)
    printSlice(s)

    // The slice grows as needed.
    s = append(s, 1)
    printSlice(s)

    // We can add more than one element at a time.
    s = append(s, 2, 3, 4)
    printSlice(s)
}

func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

笔记

  1. func append(s []T, vs …T) []T 函数原型

  2. 注意第三次追加,cap自动扩充到2^ 3 = 8

  3. 那如果再超过当前的cap呢

  4. 比如 s = append(s, 5,6,7,8),cap会自动扩容到2^4 = 16

  5. len=9 cap=16 [0 1 2 3 4 5 6 7 8]
    
  6. 这难道底层是采用hash+链表实现的吗?还有自动扩容这一说?

  7. Go 切片:用法和本质

range.go

package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
    for i, v := range pow {
        fmt.Printf("2**%d = %d\n", i, v)
    }
}

笔记

  1. 这不就是PHP数组的遍历,键值对吗?

rang-continued.go

package main

import "fmt"

func main() {
    pow := make([]int, 10)
    for i := range pow {
        pow[i] = 1 << uint(i) // == 2**i
    }
    for _, value := range pow {
        fmt.Printf("%d\n", value)
    }
    for value := range pow {
        fmt.Printf("%d\n", value)
    }
    for key, _ := range pow {
        fmt.Printf("%d\n", key)
    }
}

笔记

  1. 输出键值对的方法。

思考总结

操作数组切片的方法。
1. make
2. append

参考链接

  1. 切片
  2. 切片就像数组的引用
  3. 切片文法
  4. 切片的默认行为
  5. 切片的长度与容量
  6. nil 切片
  7. 用 make 创建切片
  8. 切片的切片
  9. 向切片追加元素
  10. Range
  11. Range续

发表评论

电子邮件地址不会被公开。 必填项已用*标注