Go语言入门(三)数组和切片

时间:2022-07-25
本文章向大家介绍Go语言入门(三)数组和切片,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

数组和切片

数组

定义:同一类型的元素集合

var a[3]int    //定义一个数组,数组的下标是从0开始,长度为n的数组下标的有效范围是0到n-1
func arraySet() {
   var a[6] int
   a[0] = 1
   a[1] = 2
   fmt.Printf("array is %vn",a)
   var b[3]int = [3]int{1,2,3}
   fmt.Println(b)
   c := [...]int{1,3,4}
   fmt.Println(c)
   d := [3]int{10}
   fmt.Println(d)
   e := [3]int{2:10}   // 下标为2的值设置为10
   fmt.Println(e)
}

数组要保持类型一致,长度一致,这样才能做等值的赋值

数组遍历

func loopArray() {
   a := [...]int{1,2,3,4,5,6,7,8,9,10}
   for index,val := range a {
      fmt.Printf("index:%dtvalue:%dn",index,val)
   }
   b := [6]string{"a","b","c","d","e","f"}
   for i:=0;i<len(b);i++ {
      fmt.Printf("index:%dtvalue:%sn",i,b[i])
   }
}

二维数组与遍历

func doubleArray() {
   var a[3][2]string = [3][2]string{
      {"lion","tiger"},
      {"cat","dog"},
      {"pig","pigwan"},
   }
   fmt.Println(a)
}
func printArray(a[3][2]string) {
   for _,v1 := range a {
      for _,v2 := range v1 {
         fmt.Printf("%sn",v2)
      }
      fmt.Printf("n")
   }
}
func main() {
   loopArray()
   doubleArray()
   var b[3][2] string
   b[0][0] = "apple"
   b[0][1] = "banana"
   b[1][0] = "sumsung"
   b[1][1] = "huawei"
   b[2][0] = "茄子"
   b[2][1] = "鸡儿"
   printArray(b)
}

数组拷贝和传参

  • 数组是值类型
func transArray() {
   var a [3]int
   a[0] = 10
   a[1] = 20
   a[2] = 30
   b := a
   b[0] = 1000
   fmt.Println(a,b)
   fmt.Printf("%pt%pn",&a,&b)
}

func modifyB(b [3]int) {
   b[0] = 1000
   return
}

切片

定义

  • 基于数组类型的一层封装。非常灵活,可以扩容
  • 切片初始化,a[start:end]创建一个包括从start到end-1的切片
  • 数组是值类型,切片是引用类型
func modifySlice() {
   //定义数组
   darr := [...]int{157,89,90,82,100,78,67,69,59}
   // 创建切片
   dslice := darr[2:5]
   fmt.Printf("slice before %vn",dslice)
   fmt.Printf("array before %vn",darr)
   for i := range dslice {
      dslice[i] ++
   }
   fmt.Printf("array after %vn",darr)
   fmt.Printf("after slice %vn",dslice)
}

切片的基本操作

  • arr[start:end] : 包括start到end-1之间的所有元素
  • arr[start:] : 包括start开始到最后一个元素之间所有的元素
  • arr[:end]: 包括从0开始到end-1之间的所有元素
  • arr[:] :包括整个数组所有的元素

使用make创建切片

func makeSlice() {
   i := make([]int,5,10)
   i[0] = 0
   i[1] = 1
   i[2] = 2
   i[3] = 3
   i = append(i, 5)   //从长度+1开始append
   i = append(i,6,7,8,9,10,11,12,13)   // 追加多个值,自动扩容
   fmt.Printf("%vtlen %dtcap %dn",i,len(i),cap(i))
}

切片拷贝

func rewriteSlice() {
   var a[]int = make([]int,5,5)
   b := a
   fmt.Printf("【修改前】a的地址%p,a的值%v;b的地址%p,b的值%vn",&a,a,&b,b)
   a = append(a,10)    //a的地址和
   fmt.Printf("【修改后】a的地址%p,a的值%v;b的地址%p,b的值%vn",&a,a,&b,b)
}

切片的再切片

func sliceAgain() {
   var a []int
   var b [6]int = [6]int{1,2,3,4,5,6}
   a = b[0:4]
   fmt.Printf("a的长度%d,容量%d,类型%Tn",len(a),cap(a),a)
   c := b[1:4]
   fmt.Printf("c的长度%d,容量%d,类型%Tn",len(c),cap(c),c)   //c的长度是3,容量是5,因为开头从1开始,引用底层的b也就少了一位

   d := a[0:2]
   fmt.Printf("d的长度%d,容量%d,类型%Tn",len(d),cap(d),d)    //d是a的切片的再切片,所以容量和a一致,长度以截取的长度为准
}

空切片

var a []int    //未被初始化,没有分配长度和容量(没有内存空间),所以称之为空切片,append可以自动扩容,免去初始化的过程,nil是个空地址的意思
func noneSlice() {
   var name []string
   if name == nil {
      fmt.Printf("this is none slice %vn",name)
      name = append(name, "wanghui","devops")
      fmt.Printf("none slice append value %vn",name)
   }
}
// 切片的append
func appendSlice() {
   var b []int = []int{1,2,3,4}
   var a []int
   a = append(a,b...)    //在a里面追加b(...就是展开b的元素的意思)
}

切片传参

证明切片是引用传递

func transArgs(a []int) {
   fmt.Printf("%pn",a)
   for i := range a{
      a[i] = 111
      fmt.Println(a[i])
   }
}

func main() {
   nums := []int{1,2,3,4}
   fmt.Printf("%pn",nums)
   transArgs(nums)
   fmt.Printf("%pn",nums)    // 参数会被改变
}

切片的拷贝

copy(dest,src) 拷贝之后,各自的地址不会发生改变,只是拷贝目的地的值发生了改变

func copySlice() {
   a := []int{1,2,3}
   b := []int{7,8}
   copy(b,a)
   fmt.Printf("a=%v,len(a)=%d,addr(a)=%ptb=%v,len(b)=%d,addr(b)=%pn",
      a,len(a),&a,
      b,len(b),&b)
}

课后作业与参考

  • 求数组的所有元素之和
func arraySum() {
   var arr [10]int
   for i:=0;i<len(arr);i++ {
      arr[i] = rand.Intn(10000)
   }

   var sum int
   for j:=0;j<len(arr);j++ {
      sum += arr[j]
   }
   fmt.Printf("arr is %vnsum=%dn",arr,sum)
}
  • 找出数组中指定元素相加等于8的下标 比如 arr := []int{1,3,5,8,7} ,下标分别是(0,4),(1,2)
func indexReturn() {
   //gen array
   var arr [10]int
   for i:=0;i<len(arr);i++ {
      arr[i] = i
   }
   //calc
   fmt.Println(arr)
   for i:=0;i<len(arr);i++ {
      for j:=i+1;j<len(arr);j++ {
         if (arr[j]+arr[i]==12) {
            fmt.Printf("arr下标和等于12的下标是i=%d,j=%dn",i,j)
         }
      }
   }
}
  • 使用sort函数进行数组排序
func useSort() {
   var arr [10]int
   for i:=0;i<len(arr);i++ {
      arr[i] = rand.Intn(10000)
   }

   fmt.Printf("before sort %vn",arr)
   sort.Ints(arr[:])

   fmt.Printf("after sort %vn",arr)
}
  • 实现一个密码生成工具,支持以下功能
    • 指定密码长度,默认16位
    • 使用类型选择,生成不同类型的密码
package main

import (
   "flag"
   "fmt"
   "math/rand"
   "time"
)

var (
   numCharset = "0123456789"
   strCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
   mixCharset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
   advanceCharset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()"
)

func geneLetter() {
   //获取26个字母
   start := 'A'
   for i:=0;i<26;i++{
      fmt.Printf("%c",start)
      start += 1
   }
}

func main() {
   var length int
   var charset string
   flag.IntVar(&length,"l",16,"-l the length of passwd")
   flag.StringVar(&charset,"t","mix","-t the charset of passwd")
   flag.Parse()

   rand.Seed(time.Now().UnixNano())

   var userCharset string

   switch charset {
   case "num":
      userCharset = numCharset
   case "char":
      userCharset = strCharset
   case "mix":
      userCharset = mixCharset
   case "advance":
      userCharset = advanceCharset
   default:
      userCharset = mixCharset
   }

   var password []byte
   for i:=0;i < length;i++ {
      index := rand.Intn(len(userCharset))
      char := userCharset[index]
      password = append(password,char)
   }
   strPassword := string(password)
   fmt.Printf("生成的密码是%sn",strPassword)
}