Golang中出场率最高的数据类型是切片,切片是基于数组类型做的一层封装的 引用类型。它非常灵活,支持自动扩容。

下面我们做几道切片题:

1.第一题

切片表达式

切片的底层就是一个数组,所以我们可以基于数组通过 切片表达式 得到想要的切片。

func main(){
    array := [...]int{1, 2, 3, 4, 5}
    s1 := array[:2] //左开右闭(x)  1 2 3   左闭右开(√) 1,2
    s2 := array[2:] //4 5(x)   3 4 5

    fmt.Println(s1)
    fmt.Println(s2)
}

关键字: 左闭右开 ,索引左闭右开

[1 2]
[3 4 5]

2.第二题

append情景1

通过内置的append()方法为切片添加元素:

func main(){
    array := [...]int{1, 2, 3, 4, 5}
    s1 := array[:2]
    s2 := array[2:]
    s1 = append(s1, 999)
	fmt.Println(array)
	fmt.Println(s1)
	fmt.Println(s2)
    fmt.Printf("array:%v len(array):%v cap(array):%v\n", array, len(array), cap(array))
	fmt.Printf("s1:%v len(s1):%v cap(s1):%v\n", s1, len(s1), cap(s1))
	fmt.Printf("s2:%v len(s2):%v cap(s2):%v\n", s2, len(s2), cap(s2))
    //Consider
}

输出

[1 2 999 4 5]
[1 2 999]
[999 4 5]
array:[1 2 999 4 5] len(array):5 cap(array):5
s1:[1 2 999] len(s1):3 cap(s1):5
s2:[999 4 5] len(s2):3 cap(s2):3

结论

为切片添加元素:

  • 一直指向底层的数组不变:所以s1的容量一直都是5;
  • 一直指向底层的数组不变:所以数组本身,以及后续切片表达式得到的切片都会发生变化

append情景2

func main(){
    array := [...]int{1, 2, 3, 4, 5}
    s1 := array[:2]
    s2 := array[2:]
	s1 = append(s1, 999, 888, 777)
	fmt.Println(array)
	fmt.Println(s1)   
	fmt.Println(s2)  
    fmt.Printf("array:%v len(array):%v cap(array):%v\n", array, len(array), cap(array))
	fmt.Printf("s1:%v len(s1):%v cap(s1):%v\n", s1, len(s1), cap(s1))
	fmt.Printf("s2:%v len(s2):%v cap(s2):%v\n", s2, len(s2), cap(s2))
    //Consider
}

输出

[1 2 999 888 777]
[1 2 999 888 777]
[999 888 777]
array:[1 2 999 888 777] len(array):5 cap(array):5
s1:[1 2 999 888 777] len(s1):5 cap(s1):5
s2:[999 888 777] len(s2):3 cap(s2):3

结论

为切片添加元素:

  • 一直指向底层的数组不变:所以s1的容量一直都是5;
  • 一直指向底层的数组不变:所以数组本身,以及后续切片表达式得到的切片都会发生变化

append情景3

func main(){
    array := [...]int{1, 2, 3, 4, 5}
    s1 := array[:2]
    s2 := array[2:]
	s1 = append(s1, 999, 888, 777, 666)
	fmt.Println(array)
	fmt.Println(s1)   
	fmt.Println(s2)  
    fmt.Printf("array:%v len(array):%v cap(array):%v\n", array, len(array), cap(array))
	fmt.Printf("s1:%v len(s1):%v cap(s1):%v\n", s1, len(s1), cap(s1))
	fmt.Printf("s2:%v len(s2):%v cap(s2):%v\n", s2, len(s2), cap(s2))
    //Consider
}

输出

[1 2 3 4 5]
[1 2 999 888 777 666]
[3 4 5]
array:[1 2 3 4 5] len(array):5 cap(array):5
s1:[1 2 999 888 777 666] len(s1):6 cap(s1):10
s2:[3 4 5] len(s2):3 cap(s2):3

结论

为切片添加元素:

  • 如果切片append后的长度超越了容量,这时底层数组将会更换,且容量也会相应增加,原有的底层数组保持不变,原有的其他切片表达式也保持不变。

总结论

为切片添加元素:

  • append后,len(slice)≤cap(slice),会影响到底层数组,以及其他切片表达式切片。
  • append后,len(slice)>cap(slice),会更换底层数组,并不影响原来的数组及其他切片表达式。

3.第三题

看题

func main(){
    array := [...]int{1, 2, 3, 4, 5}
    s1 := array[:2:2]//=>[0:2:2]
    s2 := array[2:]
	fmt.Printf("array:%v len(array):%v cap(array):%v\n", array, len(array), cap(array))
	fmt.Printf("s1:%v len(s1):%v cap(s1):%v\n", s1, len(s1), cap(s1))
	fmt.Printf("s2:%v len(s2):%v cap(s2):%v\n", s2, len(s2), cap(s2)) 
    //Consider
}

输出

array:[1 2 3 4 5] len(array):5 cap(array):5
s1:[1 2] len(s1):2 cap(s1):2  #切片容量只有2
s2:[3 4 5] len(s2):3 cap(s2):3

完整的切片表达式

a[low : high : max] 
//等价于=>
a[low: high]

0 <= low <= high <= max <= cap(a),所以s1:=array[:2:6]就会报错:

invalid slice index 6 (out of bounds for 5-element array)

完整的切片表达式它得到的结果切片的容量设置为 max-low。在完整切片表达式中只有第一个索引值(low)可以省略;它默认为0。

4.思考题

留一道题,把下面当做面试题试试,没有运行环境,手写答案:

func main(){
    array := [...]int{1, 2, 3, 4, 5}
    s1 := array[:2:2]
    s2 := array[2:]
    fmt.Println(s1) //[1 2]
	fmt.Println(s2) //[3 4 5]
	s1 = append(s1, 999)
	fmt.Println(array) //? give your answer
	fmt.Println(s1) //? give your answer
	fmt.Println(s2) //? give your answer
    //Consider
}