• 切片声明 切片在内存中的组织方式 reslice


    数组是具有相同 唯一类型 的一组已编号且长度固定的数据项序列(这是一种同构的数据结构),[5]int和[10]int是属于不同类型的。数组的编译时值初始化是按照数组顺序完成的(如下)。

    切片声明方式,

    声明切片的格式是: var identifier []type(不需要说明长度)。

    一个切片在未初始化之前默认为 nil,长度为 0。

    切片的初始化格式是:var slice1 []type = arr1[start:end]

    一个由数字 1、2、3 组成的切片可以这么生成:s := [3]int{1,2,3}[:](注: 应先用s := [3]int{1, 2, 3}生成数组, 再使用s[:]转成切片) 甚至更简单的 s := []int{1,2,3}

    切片也可以用类似数组的方式初始化:var x = []int{2, 3, 5, 7, 11}。这样就创建了一个长度为 5 的数组并且创建了一个相关切片。

    Go 切片:用法和本质 - Go 语言博客 https://blog.go-zh.org/go-slices-usage-and-internals

    可能的“陷阱”

    正如前面所说,切片操作并不会复制底层的数组。整个数组将被保存在内存中,直到它不再被引用。 有时候可能会因为一个小的内存引用导致保存所有的数据。

    例如, FindDigits 函数加载整个文件到内存,然后搜索第一个连续的数字,最后结果以切片方式返回。

    var digitRegexp = regexp.MustCompile("[0-9]+")
    
    func FindDigits(filename string) []byte {
        b, _ := ioutil.ReadFile(filename)
        return digitRegexp.Find(b)
    }

    这段代码的行为和描述类似,返回的 []byte 指向保存整个文件的数组。因为切片引用了原始的数组, 导致 GC 不能释放数组的空间;只用到少数几个字节却导致整个文件的内容都一直保存在内存里。

    要修复整个问题,可以将感兴趣的数据复制到一个新的切片中:

    func CopyDigits(filename string) []byte {
        b, _ := ioutil.ReadFile(filename)
        b = digitRegexp.Find(b)
        c := make([]byte, len(b))
        copy(c, b)
        return c
    }

    可以使用 append 实现一个更简洁的版本。这留给读者作为练习。

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    func main() {
    	x := [3]int{1, 2, 3}
    	func(arr [3]int) {
    		arr[0] = 7
    		fmt.Println(arr)
    	}(x)
    	fmt.Println(x)
    	
    	y := [3]int{1, 2, 3}
    	func(arr *[3]int) {
    		arr[0] = 7
    		fmt.Println(arr)
    		fmt.Println(*arr)
    	}(&y)
    	fmt.Println(y)
    	
    	z := []int{1, 2, 3}
    	func(arr []int) {
    		arr[0] = 7
    		fmt.Println(arr)
    	}(z)
    	
    	fmt.Println(z)
    	
    	fmt.Println("reflect.TypeOf(x,y,z:", reflect.TypeOf(x), reflect.TypeOf(y), reflect.TypeOf(z))
    }
    

      

    1、数组,值类型

    2、数组地址,修改了数组

    3、切片,引用类型,修改了数组


    [7 2 3]
    [1 2 3]
    &[7 2 3]
    [7 2 3]
    [7 2 3]
    [7 2 3]
    [7 2 3]
    reflect.TypeOf(x,y,z: [3]int [3]int []int

    the-way-to-go_ZH_CN/07.2.md at master · unknwon/the-way-to-go_ZH_CN https://github.com/unknwon/the-way-to-go_ZH_CN/blob/master/eBook/07.2.md

    切片(slice)是对数组一个连续片段的引用,切片在内存中的组织方式实际上是一个有 3 个域的结构体:指向相关数组的指针,切片长度以及切片容量。

    你真的懂 golang reslice 吗 | HHF技术博客 https://www.haohongfan.com/post/2020-10-20-golang-slice/

    分片截取也叫reslice

    如果你知道这些, 那么 slice 的使用基本上不会出现问题.

    下面这些问题你考虑过吗 ?

    1. a1, a2 是如何共享底层数组的?
    2. a1[low:high]是如何实现的?

    继续来看这段代码的汇编:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    "".a STEXT size=117 args=0x18 locals=0x18
    	// 省略...
    	0x0028 00040 (main.go:4)	CALL	runtime.newobject(SB)
    	0x002d 00045 (main.go:4)	MOVQ	8(SP), AX
    	0x0032 00050 (main.go:4)	MOVQ	$3, (AX)
    	0x0039 00057 (main.go:4)	MOVQ	$4, 8(AX)
    	0x0041 00065 (main.go:4)	MOVQ	$5, 16(AX)
    	0x0049 00073 (main.go:4)	MOVQ	$6, 24(AX)
    	0x0051 00081 (main.go:4)	MOVQ	$7, 32(AX)
    	0x0059 00089 (main.go:4)	MOVQ	$8, 40(AX)
    	0x0061 00097 (main.go:5)	ADDQ	$16, AX
    	0x0065 00101 (main.go:6)	MOVQ	AX, "".~r0+32(SP)
    	0x006a 00106 (main.go:6)	MOVQ	$4, "".~r0+40(SP)
    	0x0073 00115 (main.go:6)	MOVQ	$4, "".~r0+48(SP)
    	0x007c 00124 (main.go:6)	MOVQ	16(SP), BP
    	0x0081 00129 (main.go:6)	ADDQ	$24, SP
    	0x0085 00133 (main.go:6)	RET
    	// 省略....
    
    • 第4行: 将 AX 栈顶指针下移 8 字节, 指向了 a1 的 data 指向的地址空间里
    • 第5-10行: 将 [3,4,5,6,7,8] 放入到 a1 的 data 指向的地址空间里
    • 第11行: AX 指针后移 16 个字节. 也就是指向元素 5 的位置
    • 第12行: 将 SP 指针下移 32 字节指向即将返回的 slice (其实就是 a2 ), 同时将 AX 放入到 SP. 注意 AX 放入 SP 里的是一个指针, 也就造成了a1, a2是共享同一块内存空间的
    • 第13行: 将 SP 指针下移 40 字节指向了 a2 的 len, 同时 把 4 放入到 SP, 也就是 len(a2) = 4
    • 第14行: 将 SP 指针下移 48 字节指向了 a2 的 cap, 同时 把 4 放入到 SP, 也就是 cap(a2) = 4

    下图是 slice 的 栈图, 可以配合着上面的汇编一块看.

  • 相关阅读:
    完整的网站开发技术学习建议
    在微信小程序中绘制图表(part2)
    原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
    第八届蓝桥杯第二题:等差素数列
    第七届蓝桥杯第四题:快速排序
    51Nod:1086背包问题 V2
    POJ:2386 Lake Counting(dfs)
    51Nod:1268 和为K的组合
    迭代器
    51Nod:1134 最长递增子序列
  • 原文地址:https://www.cnblogs.com/rsapaper/p/9492313.html
Copyright © 2020-2023  润新知