答:指针和引用可以用洋葱来举例
先声明并赋值变量A,
再声明一个指向A的指针变量Z1
再声明一个指向Z1的指针变量Z2
再声明一个指向Z2的指针变量Z3
变量的左边, 加一个&引用符号 , 就像加了一层洋葱皮
如果加多个&符号,就像加了多层皮
要剥开层层洋葱皮, 就必须在左侧加 *, 直到看到对象本身数据
例如:如果想通过Z3访问A 就要根据&引用嵌套层数, 加*展开 (***Z3)
A := "hello"
Z1 := &A
Z2 := &Z1
Z3 := &Z2
fmt.Println(A,Z1, Z2, Z3, *Z3, **Z3, ***Z3)
// hello 0xc00004a3a0 0xc000006060 0xc000006068 0xc000006060 0xc00004a3a0 hello
go语言与c 语言
go是为了兼容c和c++, 并简化c的一种语言
go比java 复杂,例如:保留了指针概念,
但是比c++更高效和安全
本质是一样的,用法也差不多, 但是也有改进之处
go与c 的指针结构示意
引用值
指针 1地址
go比c的引用更直观
“c语言” 在输出结构体变量的引用结果时, 显示变量的地址
“go语言” 在输出结构体变量的引用结果时, 会显示成 “&变量”,而不是变量的地址
因为本质并没有改变,所以我认为它这么设计的原因只是为了方便调试
import "fmt"
type Tt1 struct {
ss string
}
func p1() Tt1 {
var t1 Tt1
t1 = Tt1{
"dfsg",
}
fmt.Println("1.1", t1, &t1)
t2 := t1
fmt.Println("1.2", t2, &t2)
// var t3 *Tt1
t3 := &t1
fmt.Println("1.3", t3, &t3, *t3)
t4 := t3
fmt.Println("1.4", t4, &t4, *t4)
t5 := &t3
fmt.Println("1.5", t5, &t5, *t5, **t5)
t7 := unsafe.Pointer(&t1)
fmt.Println("1.7", t7, &t7)
return t1
}
func p2() *Tt1 {
//var t1 *Tt1
t1 := &Tt1{
"dfsg",
}
fmt.Println("2.1", t1, &t1, *t1)
return t1
}
func p3() {
//普通变量
d1 := "sdfasf"
fmt.Println("3.1", d1, &d1)
d2 := 123
fmt.Println("3.2", d2, &d2)
// 非普通变量
d3 := [4]byte{1, 3, 4}
fmt.Println("3.3", d3, &d3)
d4 := []byte{1, 3, 4}
fmt.Println("3.4", d4, &d4)
}
func p4() {
A := "hello"
Z1 := &A
Z2 := &Z1
Z3 := &Z2
fmt.Println("4.1", A,Z1, Z2, Z3, *Z3, **Z3, ***Z3)
}
func main() {
t1 := p1()
fmt.Println("1", t1, &t1)
t2 := p2()
fmt.Println("2", t2, &t2)
p3()
p4()
}
输出结果是
1.1 {dfsg} &{dfsg}
1.2 {dfsg} &{dfsg}
1.3 &{dfsg} 0xc000096558 {dfsg}
1.4 &{dfsg} 0xc000096560 {dfsg}
1.5 0xc000096558 0xc000096568 &{dfsg} {dfsg}
1.7 0xc0000a7020 0xc000096570
1 {dfsg} &{dfsg}
2.1 &{dfsg} 0xc000096580 {dfsg}
2 &{dfsg} 0xc000096578
3.1 sdfasf 0xc0000a7140
3.2 123 0xc000086480
3.3 [1 3 4 0] &[1 3 4 0]
3.4 [1 3 4] &[1 3 4]
4.1 hello 0xc00004a3a0 0xc000006060 0xc000006068 0xc000006060 0xc00004a3a0 hello