go 切片

Golang piniu 1272浏览 0评论

1.切片的介绍

Go 语言切片是对数组的抽象。

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。

2.切片的定义:

你可以声明一个未指定大小的数组来定义切片:

var variable []type

切片不需要说明长度。

或使用make()函数来创建切片:

var s1 []type = make([]type, len)

//也可以简写为
s1 := make([]type, len)

//也可以指定容量,其中capacity为可选参数。
make([]T, length, capacity)

这里 len 是数组的长度并且也是切片的初始长度。

3.使用切片

//方式1:定义一个切片,用切片去引用前面创建好的数组
var arr [5]int = [...]int{1, 2, 3, 4, 5}
slice1 := arr[1:3]

//方式2:通过make来创建切片
var slice2 []int = make([]int, 4, 10)

//方式3:定义一个切片,直接指定一个数组
var slice []int = []int{1, 3, 5}
var strSlice []string = []string{"tom", "jack", "mary"}

切片的注意事项

  • 1、切片初始化时 var slice = arr[startIndex,endIndex]
    • 说明:从arr数组下标为startIndex,取到下标为endIndex的元素(不含arr[endIndex])
  • 2、切片初始化时,仍然不能越界
    • var slice = arr[0:end] 可以简写 var slice = arr[:end]
    • var slice = arr[start:len(arr)]可以简写var slice = arr[start:]
    • var slice = arr[0:len(arr)] 可以简写 var slice = arr[:]
  • 3、cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素。
  • 4、切片定义完后,还不能使用,因为本身是一个空,需要让其引用一个数组或或者make一个空间供切片来使用。
  • 5、切片可以继续切片

示例DEMO

package main

import (
	"fmt"
)

func main() {
    //定义一个数组
    var intArr [5]int = [...]int{1, 22, 33, 66, 99}
	
    //定义一个切片
    //slice是一个切片
    //引用了intArr数组的,起始下标为1,终止下标为3(但是不包含3)
    slice := intArr[1:3]
    fmt.Println("intArr数组元素是 ", intArr)
    fmt.Println("slice切片的元素是 ", slice)

    fmt.Println("slice切片的长度是 ", len(slice))
    fmt.Println("slice切片的容量是 ", cap(slice)) //容量 cap
	
    //打印intArr[1]的内存中的地址  %p 格式化为0x开头的十六进制
    fmt.Printf("intArr[1]的地址=%p\n", &intArr[1])
	
    //打印slice的地址
    fmt.Printf("slice[0]的地址=%p\n", &slice[0])
    slice[1] = 34
    fmt.Println()

    fmt.Println("intArr数组元素是 ", intArr)
    fmt.Println("slice切片的元素是 ", slice)
}

输出结果:

intArr数组元素是  [1 22 33 66 99]
slice切片的元素是  [22 33]
slice切片的长度是  2
slice切片的容量是  4
intArr[1]的地址=0xc00006c068
slice[0]的地址=0xc00006c068

intArr数组元素是  [1 22 34 66 99]
slice切片的元素是  [22 34]

由此可得出结论:切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用类型的传递机制。

4.遍历切片

for 和 for range两种方式

package main

import (
	"fmt"
)
func main() {
    var arr [5]int = [...]int{10, 20, 30, 40, 50}
    slice := arr[1:4] //20,30.40
    fmt.Println("--- for ---")
    for i := 0; i < len(slice); i++ {
        fmt.Printf("i=%v v=%v \n", i, slice[i])
    }
	
    fmt.Println("--- for range ---")
    for i, v := range slice {
        fmt.Printf("i=%v v=%v \n", i, v)
    }
}

//Output
//--- for ---
//i=0 v=20
//i=1 v=30
//i=2 v=40
//--- for range ---
//i=0 v=20
//i=1 v=30
//i=2 v=40

append增加元素或切片

var slice []int = []int{100, 200, 300}
fmt.Println("slice=", slice)  //输出:slice= [100 200 300]
//通过append直接给slice追加具体的元素。元素类型要一致

slice = append(slice, 400, 500, 600)
fmt.Println("slice=", slice) //输出:slice= [100 200 300 400 500 600]

//切片追加切片
slice = append(slice, slice...)
fmt.Println("slice=", slice) //输出:slice= [100 200 300 400 500 600 100 200 300 400 500 600]

append操作的底层原理分析:

  • 切片append操作的本质就是对数组扩容
  • go底层会创建一下新的数组newArr(按扩容后大小)
  • 将slice原来包含的元素拷贝到新的数组newArr
  • slice重新引用到newArr
  • 注意newArr是在底层来维护的。程序员不可见。

切片的copy(拷贝)

var slice1 []int = []int{1, 2, 3, 4, 5}
var slice2 = make([]int, 10)

copy(slice2, slice1)  ////将slice1的内容拷贝到slice2中

fmt.Println("slice1=", slice1)  //slice1= [1 2 3 4 5]
fmt.Println("slice2=", slice2)  //slice2= [1 2 3 4 5 0 0 0 0 0]

slice1[2] = 100

fmt.Println("修改后的slice1=", slice1)  //slice1= [1 2 100 4 5]
fmt.Println("最后slice2=", slice2)  //最后slice2= [1 2 3 4 5 0 0 0 0 0]

//copy的时候要求数据类型都是切片;
//可以看出:slice1和slice2的数据空间是独立的,相互不影响。

string 和slice

1、string底层是一个byte数组,因此string也可以进行切片处理。

str := "hello@qq.com"

//使用切片来获取数组
slice := str[6:]
fmt.Println("slice=", slice) //slice= qq.com

2、string和切片在内存的形式,以’abcd’画出内存示意图

3、string是不可变的,也就说不能通过str[0] = ‘z’方式来修改字符串

4、如果需要修改字符串,可以先将string -> []byte /或者 []rune -> 修改 -> 重写转成string

str := "hello@qq.com"

//将字符串转为byte数组
arr1 := []byte(str)
arr1[0] = 'z'

//将切片转为字符串
str = string(arr1)
fmt.Println("str = ", str)  //str =  zello@qq.com

//byte类型只能处理英文和数字,不能处理中文,原因是英文和数字占一个字节,而中文会占用3个字节,可以通过[]rune 来处理
arr2 := []rune(str)
arr2[0] = '北'

str = string(arr2)
fmt.Println("str = ", str) //str =  北ello@qq.com

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • * 昵称:
  • * 邮箱: