• Go语言学习笔记(十)之切片


    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] = 100
    
      7: 	fmt.Println(numa)
    
      8: 	nums2[1] = 101
    
      9: 	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 []int
    
      3: 	a = make([]int, 1, 10)
    
      4: 	a[0] = 10
    
      5: 	// 这里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:10
    
      2: a=[10 11 0 1] addr:0xc000014140 len:4 cap:10
    
      3: a=[10 11 0 1 2] addr:0xc000014140 len:5 cap:10
    
      4: a=[10 11 0 1 2 3] addr:0xc000014140 len:6 cap:10
    
      5: a=[10 11 0 1 2 3 4] addr:0xc000014140 len:7 cap:10
    
      6: a=[10 11 0 1 2 3 4 5] addr:0xc000014140 len:8 cap:10
    
      7: a=[10 11 0 1 2 3 4 5 6] addr:0xc000014140 len:9 cap:10
    
      8: a=[10 11 0 1 2 3 4 5 6 7] addr:0xc000014140 len:10 cap:10
    
      9: 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 []int
    
      2: fmt.Println(a, len(a), cap(a))
    
      3: a = append(a, 100)
    
      4: fmt.Println(a, len(a), cap(a))
      1: >>> [] 0 0
    
      2: [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] = 1000
    
      3: }
    
      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 main
    
      2: 
    
      3: import (
    
      4: 	"fmt"
    
      5: 	"flag"
    
      6: 	"math/rand"
    
      7: 	"time"
    
      8: )
    
      9: var (
    
     10: 	length int
    
     11: 	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 = NumStr
    
     33: 	}else if charset == "char"{
    
     34: 		sourceStr = CharStr
    
     35: 	}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 = NumStr
    
     41: 	}
    
     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:num
    
      2: sourceStr: 0123456789
    
      3: 263415358329572320363459838031515468782761014
  • 相关阅读:
    Java面向对象---重写(Override)与重载(Overload)
    Java面向对象---继承
    Java 异常处理
    Java 正则表达式
    Java 日期时间
    Java Number & Math 类
    Java StringBuffer 和 StringBuilder 类
    使用老毛桃安装Windows操作系统
    Horizon代码的层次结构
    云平台-资源监控模块和分布式日志采集系统模块
  • 原文地址:https://www.cnblogs.com/haoqirui/p/10134824.html
Copyright © 2020-2023  润新知