go函数参数总结

本文深入探讨Go语言中参数传递的原理,指出数组、结构体、字符串和整型不是指针变量,而切片和映射是。通过实例代码展示了形参与实参的关系,以及切片作为指针变量的特性。文章强调理解语言细节对于编程实践的重要性,并通过示例解释了结构体内的切片作为参数时的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学编程语言是要解决实际问题,只作“语言律师”肯定不好,只有作品才是最好的证明。

尽管如此,了解语言的基础细节可以避免我们在工作中分心,使我们专注于手头工作,免受语法或某些副作用的干扰,从这个意义上讲,了解细节是有实际意义的。

本文说明以下几个问题

一: 形参 是 实参 一个别名,形参本身也是一个变量,形参本身也有自己的地址。

二:array, struct, string, int 都不是指针变量。

三:slice指针变量 拥有的值 是 底层数组某个元素的地址。

四:只有 slice, map 才是指针变量。

以下是实际代码展示

一: 形参 是 实参 一个别名,形参本身也是一个变量,形参本身也有自己的地址。

func TestFormalParam(t *testing.T) {
	slc := []string{"a0", "a1", "a2", "a3", "a4"}
	fmt.Printf("slc=%p, &slc=%p, slc=%v\n", slc, &slc, slc)
	setValue(slc)
	fmt.Printf("slc=%p, &slc=%p, slc=%v\n", slc, &slc, slc)
}

func setValue(slc2 []string) {
	fmt.Printf("slc2=%p, &slc2=%p, slc2=%v\n", slc2, &slc2, slc2)
	slc2[0] = "诸葛村夫"
	slc2[1] = "织席贩履"
	slc2[2] = "大耳刘贼"
}

a. 实参slc 本身的地址(0xc000004520) 和 形参 slc2本身的地址(0xc000004580) 当然各不相同。

b. 实参slc 和 形参slc2 这俩指针变量 拥有值一样,即,这俩 指针变量 都指向同一 内存地址 0xc0000480f0。

二:array, struct, string, int 都不是指针变量。

func TestArray(t *testing.T) {
	arr := [5]string{"a0", "a1", "a2", "a3", "a4"}
	fmt.Printf("arr=%p, &arr=%p\n", arr, &arr)
}

a. array, struct, string, int 都是无法 %p 打印地址,编译就会报错。

b. slice, map 可以 %p 打印地址。slice变量,map变量 其实就是一根指针。

三:slice指针变量 拥有的值 是 底层数组某个元素的地址。

func TestArrayAndSlice(t *testing.T) {
	arr := [5]string{"a0", "a1", "a2", "a3", "a4"}
	for idx, _ := range arr {
		fmt.Printf("arr[%d]=%v, &arr[%d]=%p\n", idx, arr[idx], idx, &(arr[idx]))
	}
	fmt.Println()

	slc0 := arr[0:]
	fmt.Printf("slc0=%p, &slc0=%p\n", slc0, &slc0)

	slc2 := arr[2:]
	fmt.Printf("slc2=%p, &slc2=%p\n", slc2, &slc2)
}

a. slc0指针变量 拥有的值 就是 元素 arr[0]的地址。

b. slc2指针变量 拥有的值 就是 元素 arr[2]的地址。

c. 当然,指针变量本身 当然也存在地址,即:&slc0,&slc2。

四:只有 slice, map 才是指针变量。

type ComplexStruct struct {
	str  string
	num  int32
	arr  [2]string
	slc  []string
	slcC []string
	m    map[string]int32
}

func TestStruct(t *testing.T) {
	cs := ComplexStruct{
		str:  "Hello",
		num:  911,
		arr:  [2]string{"ChinaSystem", "ZTE"},
		slc:  []string{"January", "February"},
		slcC: []string{"Monday", "Tuesday"},
		m:    map[string]int32{"pow": 2, "sin": 1},
	}
	fmt.Printf("1--\ncs=%p\n%v\ncs.slcC=%p, &cs.slcC=%p\n\n", &cs, cs, cs.slcC, &cs.slcC)
	changeCS(cs)
	//入参非指针时,slc, map都会改变,其他都不会
	fmt.Printf("4--\ncs=%p\n%v\ncs.slcC=%p, &cs.slcC=%p\n\n", &cs, cs, cs.slcC, &cs.slcC)
}

func changeCS(cs ComplexStruct) {
	fmt.Printf("2--\ncs=%p\n%v\ncs.slcC=%p, &cs.slcC=%p\n\n", &cs, cs, cs.slcC, &cs.slcC)
	cs.str = "蓝色星球"
	cs.num = 9527
	cs.arr[0] = "比亚迪"
	cs.slc[0] = "十二月过年了"
	cs.slcC[0] = "星期一"
	cs.slcC = append(cs.slcC, "星期三")
	cs.slcC = append(cs.slcC, "星期四")
	cs.slcC = append(cs.slcC, "星期五")
	cs.slcC = append(cs.slcC, "星期六")
	cs.m["a平方根"] = 38
	fmt.Printf("3--\ncs=%p\n%v\ncs.slcC=%p, &cs.slcC=%p\n\n", &cs, cs, cs.slcC, &cs.slcC)
}

 A:1,2,3,4 说明:slice就是一个指针变量(再次强调)。参数传递struct时,位于struct内的

slice当然也是指针变量。

B:1,2,5,6说明:“形参是实参的别名”,这两个 指针变量 本身的地址 &cs.slcC 不同;但这两个指针变量拥有同样的值,即指向同一个内存地址 0xc00008e4e0。

C:7说明:string, int, array 都不是 指针变量(注意:array 也不是指针变量哦),所以,在另一个函数中修改后,不影响原来的值。

D:8说明:给slice append值时,由于slice扩大

    a. “形参是实参的别名”。修改cs.slcC[0]时,主调函数中的 和被调函数中的 cs.slcC 指针变量 此时还拥有同样的值,所以,修改被调函数中cs.slcC[0],主调函数中也可以看到。

    b. 在被调函数中,由于slice扩大,cs.slcC指针变量 指向的地址 从原来的地址(0xc00008e4e0)换到一个新的地址(0xc0000e6080)。

    c. 主调函数中cs.slcC指针变量 指向的地址 没有任何变化(0xc00008e4e0),回到主调函数时,只能看到a处所做的修改。

完!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值