package ch4
import(
"fmt"
)
/**
切片的内存也是在连续块中分配的。
切片是围绕这动态数组的概念构建的,可以按需自动增长和缩小。
动态增长通过内置函数append实现。
*/
func main() {
/*
创建和初始化
*/
// make和切片字面量
// 使用长度声明一个字符串切片
// 创建一个字符串切片,其长度和容量都是5个元素
slice := make([]string, 5)
// 创建一个整型切片,长度为3,容量为5
slice := make([]int, 3, 5)
// 不允许创建容量小于长度的切片
slice := make([]int, 5, 3)
// 通过切片字面量来声明切片
// 创建一个长度和容量都为5的字符串切片
slice := []string{"red", "blue", "green", "yellow", "pink"}
// 创建一个长度和容量都是3的整型切片
slice := []int{10, 20, 30}
// 使用索引声明切片
// 使用空字符串初始化第100个元素
// 如果在[]运算符里指定了一个值,那么创建的就是数组而不是切片!
slice := []string{99: ""}
// 声明数组和声明切片的不同
// 创建有3个元素的整型数组
array := [3]int{10, 20, 30}
// 创建长度和容量都是3的整型切片
slice := []int{10, 20, 30}
/*
nil和空切片
nil切片:nil指针、0长度、0容量。用来描述一个不存在的切片
空切片:地址指针、0长度、0容量。用来表示空集合
*/
// 创建nil整型切片:在声明时不做任何初始化就可以
var slice []int
// 声明空切片
// 使用make创建空的整型切片
slice := make([]int, 0)
// 使用切片字面量创建空的整型切片
slice := []int{}
/**
使用切片
*/
// 赋值和切片:
// 对切片里某个索引指向的元素赋值和对数组里某个索引指向的元素赋值完全一样
// 使用切片字面量来声明切片
slice := []int{10, 20, 30, 40, 50}
slice[1] = 25
// 使用切片创建切片
slice := []int{10, 20, 30, 40, 50}
// 创建一个长度为2,容量为4的切片,它们共享同一段底层数组
// 所以如果修改一个切片的元素,另一个切片也能感受到。
// 1代表开始的位置,3代表(开始的位置+包含的元素个数)
newSlice := slice[1:3]
/**
对底层数组容量是k的切片slice[i:j]来说
长度:j-i,上例3-1=2
容量:k-i,上例5-1=4
*/
// 修改切片内容可能导致的结果
slice := []int{10, 20,30, 40, 50}
newSlice := slice[1:3]
// 相当于也修改了slice的索引为2的元素
newSlice[1] = 35
// 表示索引越界的语言运行时错误
slice := []int{10, 20, 30, 40, 50}
newSlice := slice[1:3]
// 修改newSlice索引为3的元素
// 这个元素对于newSlice而言并不存在,所以会报错
newSlice[3] = 45
/*
切片增长
函数 append 总是会增加新切片的长
度,而容量有可能会改变,也可能不会改变,
这取决于被操作的切片的可用容量。
*/
// 使用append同时增加切片的长度和容量
slice := int[]{10, 20, 30, 40, 50}
// 向切片追加一个新元素,并将它赋值为50
// 该操作完成后,newSlice拥有一个全新的底层数组,容量为原来的两倍
// 在容量小于1000时,翻倍增长,超过1000时,增长因子会设为1.25
newSlice := append(slice, 50)
// 创建切片时的3个索引:第三个索引可以控制新切片的容量
// 创建一个切片
source := []string{"apple", "orange", "plum", "banana", "grape"}
// 将第三个元素切片,并限制容量,长度为1,容量为2
slice := source[2:3:4]
/**
对于slice[i:j:k]或[2:3:4]
长度:j-i或3-2=1
容量:k-i或4-2=2
*/
// 如果试图设置的容量比可用容量还大,就会出现一个错误
slice := source[2:3:6]
/**
内置函数 append 会首先使用可用容量。一旦没有可用容量,会分配一个
新的底层数组。这导致很容易忘记切片间正在共享同一个底层数组。
如果在创建切片时设置切片的容量和长度一样,就可以强制让新切片的第一个
append 操作创建新的底层数组,与原有的底层数组分离。
*/
// 设置长度和容量一样的好处
source := []string{"a", "b", "c", "d", "e"}
// 对第三个元素做切片,并限制长度和容量都为1,
// 如果不加第三个索引,由于剩余的所有容量都属于 slice,
// 向 slice 追加 Kiwi 会改变原有底层数组索引为 3 的元素的值 Banana。
slice := source[2:3:3]
// 向slice追加新字符串,slice会有一个新底层数组
slice = append(slice, "f")
// 将一个切片追加到另一个切片
s1 := []int{1, 2}
s2 := []int{3, 4}
// 使用...运算符,可以将一个切片的所有元素追加到另一个切片里
fmt.Printf("%v\n", append(s1, s2...))
/**
迭代切片
*/
// 使用for range迭代切片
// range会返回两个值:索引位置和对应元素的副本
slice := []int{10, 20, 30, 40}
for index, value := range slice{
fmt.Printf("index: %d value:%d\n", index, value)
}
// 使用空白标识符忽略索引值
for _, value := range slice{
fmt.Printf("value: %d\n", value)
}
// 使用传统的for循环进行迭代
for index:=2; index < len(slice); index++{
fmt.Printf("index: %d value: %d\n", index, slice[index])
}
/**
多维切片
*/
// 创建一个整型切片的切片,长度和容量都为2,因为有两个(值)数组
slice := [][]int{{10}, {100, 200}}
// 组合切片的切片
slice := [][]int{{10}, {100, 200}}
// 为第一个切片追加值为20的元素
// 先增长切片,再将新的整型切片赋值给外层切片的第一个元素
// 操作完成后,会为新的整型切片分配新的底层数组,
// 然后将切片复制到外层切片的索引为 0 的元素.即{10}变为了{10,20}
slice[0] = append(slice[0], 20)
/**
在函数间传递切片
以值的方式传递切片,因为切片的尺寸很小。
在x64上,一个切片需要24个字节的内存:每个字段8字节。
切片关联的数据不属于切片本身。复制只会复制切片本身,不会
设计到底层数组。
*/
slice := make([]int, le6)
// 将slice传递给函数foo
slice = foo(slice)
}
func foo(slice []int) []int {
return slice
}