切片不是数组,切片可以当作是没有长度的数组。更准确地理解是动态数组,底层实现和java的ArrayList一样是数组列表,底层数组的长度是切片的cap,切片目前拥有的元素数量构成了切片的len属性。当超出cap后,切片会扩容。

从字面量创建

  在学习数组的时候,看到了数组长度不一样视为不同类型,不能赋值,是不是特别痛苦?而切片是可以的,从字面量定义切片而很简单。

package main

import (
	"fmt"
)

func main() {

	slice := []rune{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	array := [...]rune{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	slice2 := []rune{0, 1, 2}
	slice = slice2
	fmt.Println(slice, array)
}

  区别仅仅在于加三个点和不加三个点。从字面量创建的切片,cap和len属性相等。

截取语法创建

 截取语法,python也有,就是中括号和冒号,go也沿用了这个语法,在go中,不仅可以截取数组,还可以截取切片。返回的就是一个切片。如下面的例子:

package main

import (
	"fmt"
)

func main() {

	array := [...]rune{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	slice1 := array[1:10]
	slice2 := slice1[2:8]
	fmt.Println(array)
	fmt.Println(slice1)
	fmt.Println(slice2)

}

  输出:

[0 1 2 3 4 5 6 7 8 9 10]
[1 2 3 4 5 6 7 8 9]     
[3 4 5 6 7 8]

make函数创建

  使用内置函数make来创建切片就很像java里的用法了。比如创建一个总容量为16,目前放置了3个元素的切片,就可以这样:

package main

import (
	"fmt"
)

func main() {
	slice := make([]rune, 3, 16)
	fmt.Println(slice, len(slice), cap(slice))
}

  输出结果:

[0 0 0] 3 16
切片共享现象

  从数组中截取出来的切片,它的指针指向了原数组。比如从数组的第2个元素开始截取,那么切片指向了原数组的第二个元素。为了证明这个现象,我写一段代码:

package main

import (
	"fmt"
)

func main() {
	array := [...]rune{0, 1, 2, 3, 4, 5, 6, 7}
	slice1 := array[:]
	slice2 := array[1:6]
	fmt.Println(slice1, slice2)
	array[3] = 99
	fmt.Println(slice1, slice2)
}

  因为都指向原数组,所以修改原数组,切片也变了,输出如下:

[0 1 2 3 4 5 6 7] [1 2 3 4 5]
[0 1 2 99 4 5 6 7] [1 2 99 4 5]
append函数

  append函数给切片追加元素,在容量不够时会自动扩容,因为扩容后会导致指针变化,所以需要将append函数返回的新地址保存下来。如以下例子:

package main

import (
	"fmt"
)

func main() {
	slice := []rune{1, 2, 3}
	fmt.Println(slice, len(slice), cap(slice))
	slice = append(slice, 4)
	fmt.Println(slice, len(slice), cap(slice))
}

  输出结果:

[1 2 3] 3 3
[1 2 3 4] 4 6
copy函数

  copy函数用起来相当于java中的addAll方法,避免手写循环。但是copy函数不会自动扩容,我写个例子就可以了:

package main

import "fmt"

func main() {
	src := []rune{1, 2, 3}
	slice := make([]rune, 1)
	copy(slice, src)
	fmt.Println(slice)
	slice = make([]rune, 5)
	copy(slice, src)
	fmt.Println(slice)

}

  输出结果:

[1]        
[1 2 3 0 0]