定义:
A方法传一个参数p 至B方法后,当B方法改变了p的值
- A方法中p值也改变了就了传指针
- A方法中p值没改变就是传值
值类型的变量:
值类型的变量是直接指向内存中的值,值都是存储在栈中,当用等号进行赋值时,实际上是进行了一次拷贝, 如 i = j 实际上是进行了一次拷贝。
GO中值类型有int ,float,bool,string等,除了数组、切片、结构体、channel外都是值类型
& 操作符会生成一个指向其操作数的指针。
* 操作符表示指针指向的底层值。
package main
import (
"fmt"
)
func main() {
fmt.Println("#### 基本类型实验")
i := "4333qw"
fmt.Println("i = ",i)
fmt.Println("&i = ",&i)
fmt.Println("*&i = ",*&i)
}
运行结果:
#### 基本类型实验
i = 9999yt
&i = 0xc00000e1e0
*&i = 9999yt
基本类型赋值
实验内容:两个基本类型之间赋值后,其中一个修改不影响另一个,他们的指针地址是不同的,是存在两个地址空间
package main
import (
"fmt"
)
func main() {
fmt.Println("#### 基本类型赋值后的实验")
i := "4333qw"
j := "9999yt"
i = j
fmt.Println("i = ",i)
fmt.Println("j = ",j)
fmt.Println("&i = ",&i)
fmt.Println("&j = ",&j)
}
引用类型赋值
实验内容:两个引用类型之间赋值后,改变其中一个值另一个值也会跟着改变,这是指针赋值,两个指针指向的是同一块内存地址
从实验可以看出 user1 = user2 的结果是user1和user2指向相同的成员变量空间,如下面代码运行结果显示,user1,user2指向的name,age的存储空间地址是相同的,所以user1.name改变后user2.name也会根着变
package main
import (
"fmt"
)
func main() {
fmt.Println()
fmt.Println("#### 引用类型实验")
user1 := new(User)
user1.name = "wq"
user1.age = 33
user2 := new(User)
user2.name = "lq"
user2.age = 22
user1 = user2
user1.name = "zs"
fmt.Println("user1.name ",user1)
fmt.Println("user2.name ",user2)
fmt.Println("&user1 ",&user1)
fmt.Println("&user2 ",&user2)
fmt.Println("&user1.name ",&user1.name)
fmt.Println("&user2.name ",&user2.name)
fmt.Println("&user1.age ",&user1.age)
fmt.Println("&user2.age ",&user2.age)
}
type User struct {
name string
age int
}
运行结果:
#### 引用类型实验
user1.name &{zs 22}
user2.name &{zs 22}
&user1 0xc00000c030
&user2 0xc00000c038
&user1.name 0xc00000a0a0
&user2.name 0xc00000a0a0
&user1.age 0xc00000a0b0
&user2.age 0xc00000a0b0
复合引用类型的赋值
实验内容:引用类型嵌套引用类型,相互赋值后引用类型成员变量也同样是指向相同的地址空间
从实验可以看出 user1 = user2 的结果是user1和user2指向相同的成员变量空间,如下面代码运行结果显示,user1.cy,user2.cy指向的存储空间地址是相同的,所以user1.cy.name改变后user3.cy.name也会根着变
package main
import (
"fmt"
)
func main() {
fmt.Println()
fmt.Println("#### 复合引用类型实验")
user1 := new(User)
user1.name = "wq"
user1.age = 33
user1.cy.name = "shanghai"
user1.cy.area = 7000000
user2 := new(User)
user2.name = "lq"
user2.age = 22
user2.cy.name = "shenzheng"
user2.cy.area = 7000000
user1 = user2
user1.cy.name = "bj"
fmt.Println("user1.cy.name ",user1.cy.name)
fmt.Println("user2.cy.name ",user2.cy.name)
fmt.Println("&user1.cy ",&user1.cy)
fmt.Println("&user2.cy ",&user2.cy)
fmt.Println("&user1.cy.name ",&user1.cy.name)
fmt.Println("&user2.cy.name ",&user2.cy.name)
fmt.Println("&user1.cy.area ",&user1.cy.area)
fmt.Println("&user2.cy.area ",&user2.cy.area)
}
运行结果:
#### 复合引用类型实验
user1.cy.name bj
user2.cy.name bj
&user1.cy &{bj 7000000}
&user2.cy &{bj 7000000}
&user1.cy.name 0xc0000621c8
&user2.cy.name 0xc0000621c8
&user1.cy.area 0xc0000621d8
&user2.cy.area 0xc0000621d8
奇怪现现解析
碰到个奇怪的问题,一下掉到思维陷进了,其实并不是很复杂,下去抽根烟上来就想通了。
现像描述:
有个切片引用类型变量slice1, 分别传入两个方法,方法1改变了slice1外面没变,方法2改变了slice1外面变了,这纠竟是为什么呢?先上代码
package main
import (
"fmt"
)
func main() {
slice1 := []string{"zhang", "san"}
fmt.Printf("&slice1 %p\n", &slice1)
modify1(slice1)
fmt.Println(slice1)
fmt.Println("----------------")
modify2(slice1)
fmt.Println(slice1)
}
func modify1(data []string) {
fmt.Printf("modify1 &data %p\n",&data)
data = nil
}
func modify2(data []string) {
fmt.Printf("modify2 &data %p\n",&data)
data[1] = "lisi"
}
运行结果:
&slice1 0xc000088020
modify1 &data 0xc000088060
[zhang san]
------------------------------
modify2 &data 0xc0000880a0
[zhang lisi]
问题:上述代码中modify1执行后slice1为什么没有变成nil呢?难道传的不是引用吗?modify2改变后外面也改变了,对于引用类型来说,这个是正常的。
解析:其实上面的代码打印过程已经给出了答案,引用类型传过去的也是值,只不过这个值是指向存储空间的指针,这个指针会在内存中开辟一块新的空间来存储。所以上面运行结果中主方法中的slice1、modify1中的data、modify2中的data的地址是不一样的,但是他们所指向的存储空间是想同的。
接下来就是问题的重点了,为啥modify1中的data=nil没有影响到外面的slice1呢,其实很简单,下面我画个图来说明这个问题
上图可以看出, modify1=nil只是切断了modify中的data与存储空间的引用关系,但并不影响外面的slice1