在最近的学习和实践中,照着别人的代码敲,仅仅只是把别人写在方法内的片段直接拿出来用,结果却出人意料,所以很纳闷!

示例代码:

1
2
3
4
5
6
7
8
func CryptBlocks(dst, src []byte) {
// ...省略内容
for len(src) > 0 {
encrypt(dst, src[:16]) //类似copy
dst = dst[16:]
src = src[16:]
}
}

这个分块处理切片数据的方法很巧妙,我第一次看见的时候(认定切片是传引用),认为这个方法错了,最终dst变成了空切片。

先看一个Slice的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import(
"fmt"
)

func main () {
var slice []int
slice = make([]int, 6)
slice = []int{0,1,2,3,4,5}
fmt.Println("Slice: ",slice)
changeSlice(slice)
fmt.Println("Changed Slice: ", slice)

}

func changeSlice(s []int) {
s[2] = 100
}

输出:

1
2
Slice:  [0 1 2 3 4 5]
Changed Slice: [0 1 100 3 4 5]

我们会发现,在方法changeSlice中对形参的修改即真实修改。如果这时我们将其定性为引用传值,为之过早!

我们将代码稍微修改一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import(
"fmt"
)

func main () {
var slice []int
slice = make([]int, 6)
slice = []int{0,1,2,3,4,5}
fmt.Printf("SliceAddr: %p , Slice: %v\r\n",&slice, slice)
changeSlice(slice)
fmt.Printf("Changed SliceAddr: %p , Changed Slice: %v\r\n", &slice, slice)

}

func changeSlice(s []int) {
fmt.Printf("In func's sliceAddr: %p\r\n", s)
s[2] = 100
}

输出:

1
2
3
SliceAddr: 0xc82000e0a0 , Slice: [0 1 2 3 4 5]
In func's sliceAddr: 0xc8200460c0
Changed SliceAddr: 0xc82000e0a0 , Changed Slice: [0 1 100 3 4 5]

由此可见,在方法内的那个s(地址:0xc8200460c0)并非传入的那个slice(地址:0xc82000e0a0),但是为什么它的修改能影响到原来的数据呢?

阅读剩下更多

默认配图