golang中的切片传递

当前有一个函数和一个结构体定义

type s struct {
	A int
}

func testFunc(l []s) {
	fmt.Printf("in testFunc: %p\n",l)
}

测试 1

我们首先传递一个切片,并打印他的内存地址

func TestA(t *testing.T)  {
	xs := s{A: 10}
	xs1 := s{A: 20}
	l := []s{xs,xs1}
	fmt.Printf("%p\n",l)
	testFunc(l)
	fmt.Printf("%p\n",l)
}
=== RUN   TestA
0xc000344800
in testFunc: 0xc000344800
0xc000344800
&l引用传递
测试 2

查阅文档, “%p”还有“fmt.Printf("%p\n",&l)”这样的打印语法, 我们来试试。

func testFunc(l []s) {
	fmt.Printf("in testFunc: %p\n",&l)
}

func TestA(t *testing.T)  {
	xs := s{A: 10}
	xs1 := s{A: 20}
	l := []s{xs,xs1}
	fmt.Printf("%p\n",&l)
	testFunc(l)
	fmt.Printf("%p\n",&l)
}
=== RUN   TestA
0xc000390d60
in testFunc: 0xc000390d80
0xc000390d60
TestAtestFunc
测试 3
unsafe
func testFunc(l []s) {
	fmt.Println("in testFunc: ",unsafe.Pointer(&l))
	fmt.Printf("in testFunc: %p\n",&l)
}

func TestA(t *testing.T)  {
	xs := s{A: 10}
	xs1 := s{A: 20}
	l := []s{xs,xs1}
	fmt.Println(unsafe.Pointer(&l))
	fmt.Printf("%p\n",&l)
	testFunc(l)
	fmt.Printf("%p\n",&l)
}
=== RUN   TestA
0xc00041a240
0xc00041a240
in testFunc:  0xc00041a260
in testFunc: 0xc00041a260
0xc00041a240
unsafe%p
func testFunc(l []s) {
	fmt.Println("in testFunc: ",unsafe.Pointer(&l),unsafe.Pointer(&(l[0])))
	fmt.Printf("in testFunc: %p\n",&l)
}

func TestA(t *testing.T)  {
	xs := s{A: 10}
	xs1 := s{A: 20}
	l := []s{xs,xs1}
	fmt.Println(unsafe.Pointer(&l),unsafe.Pointer(&(l[0])))
	fmt.Printf("%p\n",&l)
	testFunc(l)
	fmt.Printf("%p\n",&l)
}
=== RUN   TestA
0xc00000e2a0 0xc00003e280
0xc00000e2a0
in testFunc:  0xc00000e2c0 0xc00003e280
in testFunc: 0xc00000e2c0
0xc00000e2a0
l[0]0xc00003e280引用传递
测试 4

细心的小伙伴可能会提出疑问, 测试 1 打印的明明都是一样的,你这样不能自圆其说。
别着急, 那我们继续测试.

func testFunc(l []s) {
	fmt.Println("in testFunc: ",unsafe.Pointer(&l),unsafe.Pointer(&(l[0])),unsafe.Pointer(&(l[1])))
	fmt.Printf("in testFunc: %p\n",l)
}

func TestA(t *testing.T)  {
	xs := s{A: 10}
	xs1 := s{A: 20}
	l := []s{xs,xs1}
	fmt.Println(unsafe.Pointer(&l),unsafe.Pointer(&(l[0])),unsafe.Pointer(&(l[1])))
	fmt.Printf("%p\n",l)
	testFunc(l)
	fmt.Printf("%p\n",l)
}
=== RUN   TestA
0xc000418300 0xc000420140 0xc000420148
0xc000420140
in testFunc:  0xc000418340 0xc000420140 0xc000420148
in testFunc: 0xc000420140
0xc000420140
%p0("%p",l)0("%p",&l)
测试 5
引用传递
func testFunc(l []s) {
	fmt.Println("in testFunc(begin): ",l)
	l[0].A = 10
	fmt.Println("in testFunc(after): ",l)

}

func TestA(t *testing.T)  {
	xs := s{A: 10}
	xs1 := s{A: 20}
	l := []s{xs,xs1}
	fmt.Println("begin: ",l)
	testFunc(l)
	fmt.Println("after: ",l)
}
testFunc0
=== RUN   TestA
begin:  [{10} {20}]
in testFunc(begin):  [{10} {20}]
in testFunc(after):  [{1} {20}]
after:  [{1} {20}]
测试3
测试 6

那我们向切片中添加元素会发生什么?

func testFunc(l []s) {
	fmt.Println("in testFunc(begin): ",l)
	l = append(l, s{A: 30})
	fmt.Println("in testFunc(after): ",l)

}

func TestA(t *testing.T)  {
	xs := s{A: 10}
	xs1 := s{A: 20}
	l := []s{xs,xs1}
	fmt.Println("begin: ",l)
	testFunc(l)
	fmt.Println("after: ",l)
}
testFunc
=== RUN   TestA
begin:  [{10} {20}]
in testFunc(begin):  [{10} {20}]
in testFunc(after):  [{10} {20} {30}]
after:  [{10} {20}]
测试3
测试 7
测试6引用传递
func testFunc(l *[]s) {
	fmt.Println("in testFunc(begin): ",l)
	_l := *l
	_l = append(_l, s{A: 30})
	l = &_l
	fmt.Println("in testFunc(after): ",l)
}

func TestA(t *testing.T)  {
	xs := s{A: 10}
	xs1 := s{A: 20}
	l := []s{xs,xs1}
	fmt.Println("begin: ",l)
	testFunc(&l)
	fmt.Println("after: ",l)
}
append_l
=== RUN   TestA
begin:  [{10} {20}]
in testFunc(begin):  &[{10} {20}]
in testFunc(after):  &[{10} {20} {30}]
after:  [{10} {20}]

咦? 还是没变。别着急, 我们换一种写法。

func testFunc(l *[]s) {
	fmt.Println("in testFunc(begin): ",l)
	*l = append(*l, s{A: 30})
	fmt.Println("in testFunc(after): ",l)
}

func TestA(t *testing.T)  {
	xs := s{A: 10}
	xs1 := s{A: 20}
	l := []s{xs,xs1}
	fmt.Println("begin: ",l)
	testFunc(&l)
	fmt.Println("after: ",l)
}

结果

=== RUN   TestA
begin:  [{10} {20}]
in testFunc(begin):  &[{10} {20}]
in testFunc(after):  &[{10} {20} {30}]
after:  [{10} {20} {30}]

是不是变了? 至于为什么… 就交给你们写到评论里啦。

总结

("%p",l)("%p",&l)