文章目录

  • 介绍
  • 使用
  • 创建
  • 扩容
  • 复制
  • 删除
  • 遍历
  • 扩展
  • 证明切片是基于数组封装的
  • 内存地址变化的几种情况
  • 如何判断切片为空
  • 练习 - sort排序



介绍

  • 元素类型相同
  • 序列长度可变(底层实现是通过新建新数组), 支持自动扩容, 尽量避免使用
  • 引用类型
  • 三要素
  • 地址: 切片中第一个元素的内存地址 -> %p
  • 大小: 切片中当前元素的数量 -> len()
  • 容量: 切片中可容纳元素的数量 -> cap()

使用

创建

package main

import "fmt"

func main() {
	// 先声明, 再赋值
	var sliceA []int
	alice = []int{1, 2, 3}
	
	// 推导赋值
	var sliceB = []int{1, 2, 3}
	
	// 
	sliceC := []int{} // 长度和容量都为 0, 输入无法写入
	
	// 由数组获得切片, 此时的切片容量为索引起始值到数组末尾的元素数量, 索引不可超过界限
	arr := [3]int{1,2,3} // 创建数组
	sliceD := arr [:] 
	
	// 切片再切片, 索引不可超过界限
	sliceE := sliceD [1:]
	
	// make构造一个切片, 长度为0, 容量为3
	sliceF := make([]int, 0, 3) // 无法使用索引赋值
}

扩容

  • 使用 append 方法
  • 底层重建数组
  • 扩容的策略
  • 通常情况下, 为当前容量的两倍
  • 若增加的容量超过原容量的一倍, 容量=原容量+扩容容量, 遇到奇数+1
package main

import "fmt"

func main() {
	// 验证扩容后, 内存地址会发生变化
	
	a := make([]int, 0, 0)
	
	for i := 0; i < 5; i++ {
		// 使用append进行扩容, append(数组, 元素1, 元素2..)
		aa = append(aa, 1)
		fmt.Printf("aa长度为: %v; 容量为: %v; ptr为: %p\n", len(aa), cap(aa), aa)
	}
}

复制

package main

import "fmt"

func main() {
	// 由于切片是引用类型, 所以需要copy方法(深拷贝)
	a := []int{1,2,3}
	
	// 验证引用类型
	b := a
	b[0] = 100
	fmt.Println(a, b) // 结果为: [100, 2, 3] [100, 2, 3]

	// 深拷贝复制
	c := make([]int, len(a), cap(a)) // 构建一个容量和长度和 a 相同的切片
	copy(c, a)
	
	a[0] = 100
	
	fmt.Println(a, c) // [1, 2, 3] [100, 2, 3]
}

删除

package main

import "fmt"

func main() {
	// 使用append将删除元素前后连接起来
	// append用法: slice = append(slice[start:end], ele1, ele2...)
	
	a := []int{1,2,3,4,5}
	b = append(a[0:2], 4, 5)
	
	// ...的用法, 表示将切片打散为多个单一元素
	c = append(a[0:2], a[3:]...) // a[3:]... 例子中为4, 5
}

遍历

package main

import "fmt"

func main() {
	a := []int{1,2,3}
	for k,v := range a {
		fmt.Println(k,v) // k 为索引, v 为值
	}
}

扩展

证明切片是基于数组封装的

a := [...]int{1,2,3,4}
b := a[:] // 得到切片

// 对比两个内存地址, 相同则证明切片是基于数组进行封装的
fmt.Printf("%p", &a) // & 用于得到值类型的内存地址
fmt.Printf("%p", b) // 引用类型不需要&

内存地址变化的几种情况

a := [...]int{1,2,3,4}
b := a[:] // 得到切片

// 1. 当第一个元素的内存地址发生变化
c := b[1:]
fmt.Printf("%p", c) // 与a b的内存地址做对比

// 2. 容量发生变化
d := append(b, 6, 7)
fmt.Printf("%p", d) // 与a b的内存地址做对比

如何判断切片为空

package main

import "fmt"

func main() {
	// 用 3 种方法创建切片, 结果如下
	var a []int              // [], 0, 0
	b := []int{}             // [], 0, 0
	c := make([]int, 0, 100) // [], 0, 100
	
	// 但只有第一种方法创建时, 值实际为 nil
	// 所以len(slice) == 0 时, 切片为空
}

练习 - sort排序

package main

import "fmt"

func main() {
	// 使用 sort.Ints(slice)
	
	a := []int{1, 9, 8, 2, 3, 7, 6, 5, 4}

	// 使用sort对切片进行排序, 改变原切片
	sort.Ints(a)
	fmt.Println(a)
}