18 January 2016
虽然知道slice的实现,虽然也帮别人看过这个问题,但还是要被坑。

首先推荐一下雨痕大神的新书:《Golang源码剖析(第五版)》

进入正题。Golang和其它语言不通的是,他增加了一个slice,这不同于传统的数组,但是我们使用它又要按照数组的用法来,容易混淆。

先说一下我理解的传统数组,数组的名称就是数组在内存里面的首地址,访问每个子元素就是首地址加子元素长度访问。所以这应该是一个引用对象类型。

而Golang的slice,引用一下雨痕大神的文章说明:

runtime.h

struct Slice
{
	byte* array;
	uintgo len;
	uintgo cap;
}

slice底层是通过struct实现的,所以传递的时候是值拷贝传递,但是,slice的内容是通过数组指针实现的。就会发生这种现象:***通过值传递,lencap都不会变,所以使用的时候不会感觉到内容有变化,但是实际上byte数组是发生变化的。

上代码:

package main

import "fmt"

func main() {
	testMap := make(map[int64]int64)
	fmt.Println(testMap)
	FuckMap(testMap)
	fmt.Println(testMap)
	FuckMap2(testMap)
	fmt.Println(testMap)

	testSlice := []int64{}
	fmt.Println(testSlice)
	FuckSlice(testSlice)
	fmt.Println(testSlice)
	
	FuckSlice2(&testSlice)
	fmt.Println(testSlice)
}

func FuckMap(t map[int64]int64) map[int64]int64 {
	t[1] = 1
	return t
}

func FuckMap2(t map[int64]int64) map[int64]int64 {
	t[1] = 2
	return t
}

func FuckSlice(a []int64) []int64 {
	a = append(a, 1)
	return a
}

func FuckSlice2(a *[]int64) *[]int64 {
	*a = append(*a, 1)
	return a
}

直接看后半部分。FuckSlice函数对于slice的修改是不起作用的,因为slice是按值传递的;然后我们强行改成按引用传递,就是传递slice的地址作为参数,这时的修改就是起作用的。所以,对于修改slice的操作要注意,有可能会修改失败。



原文链接:狗日的slice,转载请注明来源!

EOF