关于golang:GO切片

5次阅读

共计 3438 个字符,预计需要花费 9 分钟才能阅读完成。

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

Go 数组的长度不可扭转,在特定场景中这样的汇合就不太实用,Go 中提供了一种灵便,性能强悍的内置类型切片(“ 动静数组 ”),与数组相比切片的长度是不固定的,能够追加元素,在追加时可能使切片的容量增大。

空 (nil) 切片
一个切片在未初始化之前默认为 nil,长度为 0,实例如下:

package main

import "fmt"

func main() {var numbers []int

   printSlice(numbers)

   if(numbers == nil){fmt.Printf("切片是空的")
   }
}

func printSlice(x []int){fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

切片截取
case1:foo 和 bar 的内存是共享的,所以,foo 和 bar 的对数组内容的批改都会影响到对方。

import (
    "bytes"
    "testing"
)

func TestSlice1(t *testing.T) {foo := make([]int, 5) // 首先先创立一个 foo 的 slice,其中的长度和容量都是 5
    foo[3] = 42           // 而后开始对 foo 所指向的数组中的索引为 3 和 4 的元素进行赋值
    foo[4] = 100
    t.Log("foo=", foo) // foo= [0 0 0 42 100]
    bar := foo[1:4]
    bar[1] = 99
    // foo 和 bar 的内存是共享的,所以,foo 和 bar 的对数组内容的批改都会影响到对方。t.Log("foo=", foo) // foo= [0 0 99 42 100]
    t.Log("bar=", bar) // bar= [0 99 42]
}

case2: 数据操作 append() 的示例
append() 这个函数在 cap 不够用的时候就会从新分配内存以扩充容量,而如果够用的时候不不会从新分享内存!

func TestSlice2(t *testing.T) {a := make([]int, 5)
    t.Log("a=", a, "a.len=", len(a), "a.cap=", cap(a)) // a= [0 0 0 0 0]  a.len= 5  a.cap= 5
    b := a[1:3]                                          // 此时,a 和 b 的内存空间是共享的
    t.Log("b=", b, "b.len=", len(b), "b.cap=", cap(b)) // b= [0 0]  b.len= 2  b.cap= 4
    a = append(a, 1)                                     // 这个操作会让 a 从新分享内存,导致 a 和 b 不再共享
    //b = append(b, 1)                 // 因为 b 的 cap 为 4,空间够用,因而不须要重新分配内容,此时与 a 还是共享内存
    t.Log("a=", a, "a.len=", len(a), "a.cap=", cap(a)) // a= [0 0 0 0 0 1]  a.len= 6  a.cap= 10
    t.Log("b=", b, "b.len=", len(b), "b.cap=", cap(b)) // b= [0 0]  b.len= 2  b.cap= 4
    a[2] = 42
    t.Log("a=", a, "a.len=", len(a), "a.cap=", cap(a)) // a= [0 0 42 0 0 1]  a.len= 6  a.cap= 10
    t.Log("b=", b, "b.len=", len(b), "b.cap=", cap(b)) // b= [0 0]  b.len= 2  b.cap= 4
}

case3: dir1 和 dir2 共享内存
尽管 dir1 有一个 append() 操作,然而因为 cap 足够,于是数据扩大到了 dir2 的空间。

func TestSlice3(t *testing.T) {path := []byte("AAAAxBBBBBBBBB")
    t.Log("path =>", string(path), "path.len=", len(path), "path.cap=", cap(path)) //path => AAAAxBBBBBBBBB  path.len= 14  path.cap= 14
    sepIndex := bytes.IndexByte(path, 'x')
    dir1 := path[:sepIndex]
    dir2 := path[sepIndex+1:]
    t.Log("......................................................")
    t.Log("dir1 =>", string(dir1), "dir1.len=", len(dir1), "dir1.cap=", cap(dir1)) //prints: dir1 => AAAA dir1.len= 4  dir1.cap= 14
    t.Log("dir2 =>", string(dir2), "dir2.len=", len(dir2), "dir2.cap=", cap(dir2)) //prints: dir2 => BBBBBBBBB dir2.len= 9  dir2.cap= 9

    t.Log("......................................................")
    dir1 = append(dir1, "suffix"...)
    t.Log("dir1 =>", string(dir1), "dir1.len=", len(dir1), "dir1.cap=", cap(dir1)) //prints: dir1 => AAAAsuffix dir1.len= 10  dir1.cap= 14
    t.Log("dir2 =>", string(dir2), "dir2.len=", len(dir2), "dir2.cap=", cap(dir2)) //prints: dir2 => uffixBBBB  dir2.len= 9  dir2.cap= 9

}

case4: 如果要解决这个问题,咱们只须要批改一行代码。

func TestSlice4(t *testing.T) {pathz := []byte("AAAAxBBBBBBBBB")
    sepIndex := bytes.IndexByte(pathz, 'x')
    dirz1 := pathz[:sepIndex:sepIndex] // 新的代码应用了 Full Slice Expression,其最初一个参数叫“Limited Capacity”,于是,后续的 append() 操作将会导致从新分配内存。dirz2 := pathz[sepIndex+1:]
    t.Log("dirz1 =>", string(dirz1), "dir1.len=", len(dirz1), "dir1.cap=", cap(dirz1)) //dirz1 => AAAA  dir1.len= 4  dir1.cap= 4
    t.Log("dirz2 =>", string(dirz2), "dir2.len=", len(dirz2), "dir2.cap=", cap(dirz2)) //dirz2 => BBBBBBBBB  dir2.len= 9  dir2.cap= 9
    t.Log("......................................................")
    dirz2[0] = 'o'
    t.Log("dirz1 =>", string(dirz1), "dir1.len=", len(dirz1), "dir1.cap=", cap(dirz1)) //dirz1 => AAAA  dir1.len= 4  dir1.cap= 4
    t.Log("dirz2 =>", string(dirz2), "dir2.len=", len(dirz2), "dir2.cap=", cap(dirz2)) //dirz2 => oBBBBBBBB  dir2.len= 9  dir2.cap= 9

    t.Log("......................................................")
    dirz1 = append(dirz1, "suffix"...)
    t.Log("dirz1 =>", string(dirz1), "dir1.len=", len(dirz1), "dir1.cap=", cap(dirz1)) //dirz1 => AAAAsuffix  dir1.len= 10  dir1.cap= 16
    t.Log("dirz2 =>", string(dirz2), "dir2.len=", len(dirz2), "dir2.cap=", cap(dirz2)) //dirz2 => oBBBBBBBB  dir2.len= 9  dir2.cap= 9
}

参考资料:
Go 语言切片(Slice)
GO 编程模式:切片,接口,工夫和性能

正文完
 0