15.切片
切片是基于数组类型做的一层封装。它非常灵活,可以自动扩容。
切片的定义
1: var a []int
// 定义一个int类型的空切片
// 切片不初始化是无法操作的,这点和数组不一样。
切片的初始化:
1: 1.arr[start:end]start到end-1(包括end-1)之间的所有元素2: 2.arr[start:]
3: 3.arr[:end]
4: 4.arr[:]包括整个数组的所有元素
例:
1: a := [5]int{76,77,78,79,80}2: var b []int = a[1:4]3: c:= []int{6,7,8}
切片的修改:
1: func main() {2: darr := [...]int{57,89,90,82,100,78,67,69,59}3: dslice := darr[2:5]4: fmt.Println("array before", darr)
5: for i,_ := range dslice {6: dslice[i] ++7: }8: fmt.Println("array after", darr)
9: }
//这种类似于python里的浅拷贝
1: func main() {2: numa := [3]int{78,79,80}3: nums1 := numa[:]4: nums2 := numa[:]5: fmt.Println("array before change 1", numa)
6: nums1[0] = 1007: fmt.Println(numa)8: nums2[1] = 1019: fmt.Println(numa)10: }11: >>> [100 79 80]12: [100 101 80]
使用make创建切片
1: i := make([]int, 5, 5)
// (类型 当前长度 容量上线)
// 未指定的元素默认为0
1: func main() {2: var a []int3: a = make([]int, 1, 10)4: a[0] = 105: // 这里a[1] = 20 会报错,操作越界了,这是个重要的细节,忽略很容易犯错
6: a = append(a, 11)7: fmt.Printf(a)8: }
1: >>> [10 11]
扩容(cap(a)是表示a的容量上限)
1: for i:=0;i<10;i++ {2: a = append(a, i)3: fmt.Printf("a=%v addr:%p len:%d cap:%d ", a,a,len(a),cap(a))
4: }
输出:
1: >>>a=[10 11 0] addr:0xc000014140 len:3 cap:102: a=[10 11 0 1] addr:0xc000014140 len:4 cap:103: a=[10 11 0 1 2] addr:0xc000014140 len:5 cap:104: a=[10 11 0 1 2 3] addr:0xc000014140 len:6 cap:105: a=[10 11 0 1 2 3 4] addr:0xc000014140 len:7 cap:106: a=[10 11 0 1 2 3 4 5] addr:0xc000014140 len:8 cap:107: a=[10 11 0 1 2 3 4 5 6] addr:0xc000014140 len:9 cap:108: a=[10 11 0 1 2 3 4 5 6 7] addr:0xc000014140 len:10 cap:109: a=[10 11 0 1 2 3 4 5 6 7 8] addr:0xc00008a000 len:11 cap:20
//观察扩容的结果,发现扩容的策略是翻倍扩容
1: func testCap() {2: a := [...]string{"a","b","c","d","e","f","g","h"}3: b := a[1:3]4: fmt.Printf("b:%v len:%d cap:%d ",b,len(b),cap(b))
5: }
1: >>> b:[b c] len:2 cap:7
空切片
1: var a []int2: fmt.Println(a, len(a), cap(a))3: a = append(a, 100)4: fmt.Println(a, len(a), cap(a))
1: >>> [] 0 02: [100] 1 1
切片传参
1: veggies := []string{"potatoes", "tomatoes", "brinjal"}2: fruits := []string{"oranges", "apples"}3: food := append(veggies, fruits...)4: // friuts后面的3个点表示展开fruits切片成一个个元素
5: fmt.Println(food)
1: func modifySlice(a []int) {2: a[0] = 10003: }4: func main(){5: var a [3]int = [3]int{1, 2, 3}6: modifySlice(a[:])7: fmt.Println(a)8: }
1: >>> [1000, 2, 3]
切片的拷贝
1: func main() {2: veggies := []string{"potatoes", "tomatoes", "brinjal"}3: fruits := []string{"oranges", "apples"}4: copy(veggies, fruits)
5: fmt.Println(veggies, fruits)6: }
1: >>> [oranges apples brinjal] [oranges apples]
1: func main() {2: var a := []int{1, 2}3: var a = []int{1, 2}4: var b := []int{4, 5, 6}5: copy(a, b)
6: fmt.Println(a, b)7: }
1: >>> [4 5] [4 5 6]
make和new的区别
make为内建类型为slice, map和channel分配内存
new用于各种类型的内存分配, new返回的是一个指针
几个小练习
1.下面程序输出什么
1: func main() {2: var a = make([]string, 5, 10);
3: for i:=0;i<10;i++{4: a = append(a, fmt.Sprintf("%d", i))
5: }6: fmt.Println(a)7: }
1: >>> a= [ ]2: a= [ 0 1 2 3 4 5 6 7 8 9]
2.使用golang标准包"sort"对数组进行排序
1: func main() {2: a := []int{5, 4, 3, 2, 1}3: sort.Ints(a[:])4: fmt.Println("a=",a)
5: b := []string{"f", "e", "c", "b", "a"}6: sort.Strings(b[:])7: fmt.Println("b=",b)
8: c := []float64{58.554,88.23,998.255,48.25,566.66}9: sort.Float64s(c[:])10: fmt.Println("c=",c)
11: }
3.实现一个密码生成工具,支持以下功能
PS:标准包"flag"解析命令行参数
a.用户可以通过-l指定生成让那个密码的长度
b.用户可以通过-t指定生成密码的字符集,比如-t num生成全数字的密码-t char生成包含全英文字符的密码, -t mix包含生成数字和英文的密码,-t advance生成包含数字,英文以及特殊字符的密码
1: package main2:3: import (
4: "fmt"
5: "flag"
6: "math/rand"
7: "time"
8: )9: var (10: length int11: charset string
12: )13: const (14: NumStr = "0123456789"
15: CharStr = "abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNOPQRSTUVWXYZ"
16: SpecStr = "@#$%^&*_+=/*-"
17: )18: func parseArgs() {19: flag.IntVar(&length, "l", 16, "-l 生成密码长度")20: flag.StringVar(&charset, "t", "num",21: `-t 制定密码生成的字符集,22: num:只使用数字[0-9],23: char:只使用英文字母[a-zA-Z],24: mix:使用数字和字母,25: advance:使用数字字母以及特殊字符`)26: flag.Parse()27: }28: func generatePasswd() string {
29: var password []byte = make([]byte, length, length)30: var sourceStr string
31: if charset == "num" {32: sourceStr = NumStr33: }else if charset == "char"{34: sourceStr = CharStr35: }else if charset == "mix" {36: sourceStr = fmt.Sprintf("%s%s", NumStr, CharStr)
37: }else if charset == "advance" {38: sourceStr = fmt.Sprintf("%s%s%s", NumStr, CharStr, SpecStr)
39: }else {
40: sourceStr = NumStr41: }42: fmt.Println("sourceStr:", sourceStr)
43: for i:=0;i<length;i++{44: index := rand.Intn(len(sourceStr))
45: password[i] = sourceStr[index]
46: }47: return string(password)48: }49: func main() {50: rand.Seed(time.Now().UnixNano())
51: parseArgs()52: fmt.Printf("length:%d charset:%s ", length, charset)
53: passwd := generatePasswd()54: fmt.Println(passwd)55: }
编译后输入:
1: main.exe -l 45 -t num
结果
1: length:45 charset:num2: sourceStr: 01234567893: 263415358329572320363459838031515468782761014