Talk is cheap, show me the code:)
代码:
package main
import (
"fmt"
)
// func main() {
// var x = [3]int{1, 2, 3}
// fmt.Println(arraySum(x))
// }
// func arraySum(x [3]int) int{
// sum := 0
// for i := 0; i < len(x); i++ {
// sum += x[i]
// }
// return sum
// }
// 切片(slice )
func main() {
// 声明切片类型
var a []string //切片声明但没有初始化则值为nil
// 一个nil值的切片并没有底层数组,一个Nil值的切片的长度和容量都是0
// 但不能说长度和容量都是0的切片值为nil
// var s1 []int //len(s1)=0;cap(s1)=0;s1==nil
// s2 := []int{} //len(s2)=0;cap(s2)=0;s2!=nil
// s3 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil
var b = []int{} // 声明一个整型切片并初始化,值不为nil
var c = []bool{false, true} // 声明一个布尔切片并初始化
var d = []bool{false, true} // 声明一个布尔切片并初始化
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
fmt.Println(a == nil) // true
fmt.Println(b == nil) // false
fmt.Println(d == nil) // false
// fmt.Println(c == d) //切片是引用类型,不支持直接比较
b = []int{1, 2, 3}
fmt.Println(b == nil)
a = []string{"北京", "上海", "武汉", "深圳"}
// 打印长度和容量
fmt.Printf("len(a):%d cap(a):%d\n", len(a), cap(a))
fmt.Printf("len(b):%d cap(b):%d\n", len(b), cap(b))
// 2.由数组得到切片
a1 := [...]int{1, 3, 5, 7, 9, 11, 13}
s3 := a1[0:4] // 1 3 5 7, 基于一个数组切割,左包含右不包含
fmt.Println(s3)
s4 := a1[1:6]
fmt.Println(s4)
s5 := a1[:4] // => [0:4] [1 3 5 7]
s6 := a1[3:] // => [3:len(a1)] [7 9 11 13]
s7 := a1[:] // => [0:len(a1)]
fmt.Println(s5, s6, s7)
// 切片的长度和容量
fmt.Printf("len(s5):%d cap(s5):%d\n", len(s5), cap(s5)) // len(s5):4 cap(s5):7
fmt.Printf("len(s6):%d cap(s6):%d\n", len(s6), cap(s6)) // len(s6):4 cap(s6):4
// 直接声明并初始化一个切片时,Go底层也会先分配一个数组
// 切片再切片,切片在切片的容量还是根据底层的数组(从切片的第一个元素开始)来计算
s8 := s6[3:] // [13]
fmt.Printf("len(s8):%d cap(s8):%d\n", len(s8), cap(s8)) // len(s8):1 cap(s8):1
s9 := s5[1:] // [3 5 7]
fmt.Printf("len(s9):%d cap(s9):%d\n", len(s9), cap(s9)) // len(s9):3 cap(s9):6
// 切片是引用类型,都指向了底层的一个数组
fmt.Println("s6:", s6)
a1[len(a1)-1] = 1300
fmt.Println("s6:", s6)
fmt.Println("s8:", s8)
// 上面都是通过数组创建切片,如果需要动态地创建切片,需要使用内置的make函数
// make函数的容量值省略默认是和长度相同的
s10 := make([]int, 5, 10) // make([]T, size, cap)
fmt.Printf("s10=%v len(s10)=%d cap(s10)=%d\n", s10, len(s10), cap(s10))
s11 := make([]int, 0, 10)
fmt.Printf("s11=%v len(s11)=%d cap(s11)=%d\n", s11, len(s11), cap(s11))
// 切片扩容
// append函数将元素追加到切片的最后并返回该切片
// 切片numSlice的容量按照1 2 4 8 16自动扩容,每次扩容后都是扩容前的2倍,此时切片指向的底层数组就会更换
var numSlice []int
for i := 0; i < 10; i++ {
numSlice = append(numSlice, i)
fmt.Printf("%v len:%d cap:%d ptr:%p\n", numSlice, len(numSlice), cap(numSlice), numSlice)
}
var citySlice []string
citySlice = []string{"武汉", "黄冈", "北京", "深圳"}
fmt.Println(citySlice)
// append可以添加一个元素
citySlice = append(citySlice, "上海")
fmt.Println(citySlice)
// append添加多个元素
citySlice = append(citySlice, "杭州", "广州")
// append添加切片
tailSlice := []string{"西安", "成都"}
// ...表示拆分,即将前面的切片tailSlice拆开
citySlice = append(citySlice, tailSlice...)
fmt.Println(citySlice)
// 切片的扩容策略
// 如果新申请的容量大于2倍的旧容量,最终申请的容量就是新申请的容量
// 否则,如果旧切片的长度小于1024,则最终容量就是旧容量的两倍
// 如果旧切片长度大于1024,则最终容量从旧容量开始循环增加原来的1/4
// 使用copy函数复制切片
srcSlice := []int{1, 2, 3, 4, 5}
destSlice := make([]int, 5, 5)
copy(destSlice, srcSlice)
fmt.Printf("before mutual: %v\n", srcSlice)
fmt.Printf("before mutual: %v\n", destSlice)
srcSlice[4] = 1000
fmt.Printf("after mutual: %v\n", srcSlice)
fmt.Printf("after mutual: %v\n", destSlice)
// Go语言没有删除切片元素的专用方法,可使用切片本身的特性来删除元素
origSlice := []int{1, 3, 5}
origSlice = append(origSlice[:1], origSlice[2:]...) // len(origSlice)=2 cap(origSlice)=3
fmt.Printf("origSlice:%v len(origSlice):%d cap(origSlice):%d\n", origSlice, len(origSlice), cap(origSlice))
// 一个易混淆的点:切片不占用内存
x1 := [...]int{1, 3, 5}
ss1 := x1[:]
fmt.Println(ss1, len(ss1), cap(ss1))
// 切片不保存具体的值,切片对应一个底层数组,底层数组占用一块连续内存
ss1 = append(ss1[:1], ss1[2:]...)
fmt.Println(x1) //x1:[1 5 5]
// // 第二种情况
// x1 := [...]int{1, 3, 5}
// ss1 := x1[:]
// fmt.Printf("x1:%p, ss1:%p\n", &x1[0], ss1)
// ss2 := []int{2, 4, 6}
// ss1 = append(ss1[:1], ss2...)
// fmt.Println(ss1, x1)
// fmt.Printf("x1:%p, ss1:%p\n", &x1[0], ss1)
// 切片的练习题
var aa = make([]int, 5, 10)
for ii := 0; ii < 10; ii++ {
aa = append(aa, ii)
}
fmt.Println(aa) // [0 0 0 0 0 1 2 3 4 5 6 7 8 9]
}
运行结果: