乐趣区

关于golang:Go-语言的切片使用

切片(slice)是建设在数组之上的更不便,更灵便,更弱小的数据结构。切片并不存储任何元素而只是对现有数组的援用。

切片的三要素

  • 指向数组中的开始地位
  • 切片的长度,通过内置函数 len 取得
  • 切片的最大容量,通过内置函数 cap 取得

能够认为切片在外部示意为如下的构造体:

type slice struct {
    // 长度
    Length        int
    // 容量
    Capacity      int
    // 指向首元素的指针
    ZerothElement *byte
}

切片申明

// 基于数组创立一个从 a[start] 到 a[end -1] 的切片
a := [5]int{76, 77, 78, 79, 80}
var b []int = a[1:4]

// 创立了一个长度为 4 的 string 数组,并返回一个切片给 names
names := []string{"beijing", "shanghai", "guangzhou", "shenzhen"}

// 创立长度为 10 的字符串切片
str := make([]string, 10)

// 创立长度为 10,容量为 20 的字符串切片
str := make([]string, 10, 20)

arr[start:end] 的应用

// 基于数组产生新的切片,a[start:end] 为左闭右开
name1 := names[0:3]
name2 := names[:3]
name3 := names[2:]
name4 := names[:]

援用传递

切片自身不蕴含任何数据。它仅仅是底层数组的一个下层示意。对切片进行的任何批改都将反映在底层数组中。

names := []string{"beijing", "shanghai", "guangzhou", "shenzhen"}
name1 := names[0:3]

// 援用传递,会同时扭转原数组
name1[2] = "luoyang"

fmt.Println(names)
fmt.Println(name1)

获取切片长度与容量

str := "helloworld"[5:7]
fmt.Println("len:", len(str), ", cap:", cap(str))

切片追加元素

// append 会判断切片是否有残余空间,如果没有残余空间,则会主动裁减两倍空间
names = append(names, "chongqing")

如果切片是建设在数组之上的,而数组自身不能扭转长度,那么切片是如何动静扭转长度的呢?理论产生的状况是,当新元素通过调用 append 函数追加到切片开端时,如果超出了容量,append 外部会创立一个新的数组。并将原有数组的元素被拷贝给这个新的数组,最初返回建设在这个新数组上的切片。这个新切片的容量是旧切片的二倍。

切片追加切片

能够应用 ... 操作符将一个切片追加到另一个切片开端

veggies := []string{"potatoes","tomatoes","brinjal"}
fruits := []string{"oranges","apples"}
food := append(veggies, fruits...)
fmt.Println("food:", food)

遍历切片

for key, value := range names {fmt.Println("key:", key, ", value:", value)
}

复制切片

copy 用于将内容从一个数组切片复制到另一个数组切片。

slice1 := []int{1, 2, 3, 4, 5} 
slice2 := []int{5, 4, 3} 

copy(slice2, slice1) // 只会复制 slice1 的前 3 个元素到 slice2 中 
copy(slice1, slice2) // 只会复制 slice2 的 3 个元素到 slice1 的前 3 个地位 

切片作为函数参数

func subtactOne(numbers []int) {  
    for i := range numbers {numbers[i] -= 2
    }
}

func main() {nos := []int{8, 7, 6}
    fmt.Println("slice before function call", nos)
    subtactOne(nos)                               //function modifies the slice
    fmt.Println("slice after function call", nos) //modifications are visible outside
}

// array before function call [8 7 6]  
// array after function call [6 5 4]  

切片内存优化

切片保留对底层数组的援用。只有切片存在于内存中,数组就不能被垃圾回收。假如咱们有一个十分大的数组,而咱们只须要解决它的一小部分,为此咱们创立这个数组的一个切片,并解决这个切片。这时候数组依然存在于内存中,因为切片正在援用它。

解决该问题的一个办法是应用 copy 函数来创立该切片的一个拷贝。这样咱们就能够应用这个新的切片,原来的数组能够被垃圾回收。

func countries() []string {countries := []string{"USA", "Singapore", "Germany", "India", "Australia"}
    // 数组被切片援用,不能回收
    neededCountries := countries[:len(countries)-2]
    // 创立新的切片
    countriesCpy := make([]string, len(neededCountries))
    // 应用 copy 函数创立切片的拷贝
    copy(countriesCpy, neededCountries) //copies neededCountries to countriesCpy
    // 返回后数组不再被援用,主动回收
    return countriesCpy
}

func main() {countriesNeeded := countries()
    fmt.Println(countriesNeeded)
}
退出移动版