学编程语言是要解决实际问题,只作“语言律师”肯定不好,只有作品才是最好的证明。
尽管如此,了解语言的基础细节可以避免我们在工作中分心,使我们专注于手头工作,免受语法或某些副作用的干扰,从这个意义上讲,了解细节是有实际意义的。
本文说明以下几个问题
一: 形参 是 实参 一个别名,形参本身也是一个变量,形参本身也有自己的地址。
二: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处所做的修改。
完!