切片-学习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)
}
笔记
- 创建长度为6的int数组,构建一个引用该数组的切片。
- 创建长度为6的布尔数组,构建一个引用该数组的切片。
- 创建长度为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)
}
笔记
- 切片的默认值为0到数组长度。
- 以数组var a [10]int为例
- 切片等价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 %vn", len(s), cap(s), s)
}
笔记
- 如何理解切片的长度和容量。按照正常逻辑不是只有长度就够了吗?为啥还要新增一个容量呢?
- 切片的长度就是它所包含的元素个数。
- 切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。
- 注意看第二个例子,长度变为0 ,但是容量为什么还是6呢?
- 注意第四个例子,是不是起始值变了,才会去修改引用数组的容量?
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!")
}
}
笔记
- 切片的零值是
nil
。 - 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 %vn",
s, len(x), cap(x), x)
}
笔记
- 默认创建len 和cap 相同的切片
- a := make([]int, 5) // len(a)=5 cap(a)=5
- 注意第四个例子,cap变成了3
- 假如d1 := c[3:5],那么cap会变成2
- 切片的最大值不能超过原始数组的长度,不然会报错。
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("%sn", strings.Join(board[i], " "))
}
}
笔记
- 这尼玛不是就二维数组了吗?
- 创建了一个二维数组的切片,也就是切片的切片
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 %vn", len(s), cap(s), s)
}
笔记
func append(s []T, vs …T) []T 函数原型
注意第三次追加,cap自动扩充到2^ 3 = 8
那如果再超过当前的cap呢
比如 s = append(s, 5,6,7,8),cap会自动扩容到2^4 = 16
len=9 cap=16 [0 1 2 3 4 5 6 7 8]
这难道底层是采用hash+链表实现的吗?还有自动扩容这一说?
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 = %dn", i, v)
}
}
笔记
- 这不就是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("%dn", value)
}
for value := range pow {
fmt.Printf("%dn", value)
}
for key, _ := range pow {
fmt.Printf("%dn", key)
}
}
笔记
- 输出键值对的方法。
思考总结
操作数组切片的方法。
- make
- append