值传递&引用传递
目录
1. 值类型
定义:变量直接指向存在内存中的值,我们称之为值类型。
值类型的变量的值
存储在栈中
。值类型,将一个变量赋值给另一个变量,称为
值拷贝
。
package main
import "fmt"
func main(){
var num1,num2 int
num1 = 10
num2 = num1 // 值类型赋值操作
fmt.Println(num1,num2) // 10 10
num1 = 20
fmt.Println(num1,num2) // 20 10
}
2. 指针类型
一个变量指向
内存中值所在的内存地址
,我们称这个变量为指针类型go 语言中的指针与C/C++ 中的指针用法是一样的,只是出于安全性的考虑go增加了: 1、
不同类型的指针不能互相转化
2、任何普通指针类型*T和uintptr之间不能互相转化
3、指针变量不能进行运算
package main
import "fmt"
func main(){
var num int = 100
var ptr *int // 类型前 加 * 表示这是指针类型,指针类型的初始值为nil ,和其他语言的NUll,None一样
ptr = &num // & 取num 变量的内存地址。 因为ptr 是指针,指向的是内存地址,所以需要赋值操作的是内存地址
fmt.Println("ptr 指针的值:",ptr)
fmt.Println("*ptr 指针的值:",*ptr) // * 取指针内存地址所指向的值
num = 200
fmt.Println("*ptr 指针的值:",*ptr)
}
3. 引用类型
在go语言中目前引用类型有:
切片、map、chan、func
空指针(引用): nil
4. 值接受者与指针接受者
1. 值接受者
值接受者可以给接收值、也可以接收指针,因为go会对接收的指针进行解引用。但是!
variable传递进函数的只是副本,他们都是在variable的副本上进行操作,并不影响 variable 的原本的值。
func ( variable type )Name ( InputParam ) ( OutputParam )
2. 指针接受者
指针接收者接收的是variable的值的地址,也就是说func修改了值的时候会影响 variable 原本的值。
(variable *type)func()
5. 指针与引用
- 指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个“存储单元”,即指针是一个实体;而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已。
- 可以有const指针,但是没有const引用;
- 指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)
- 指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化;
- 指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了,从一而终。
- ”sizeof引用”得到的是所指向的变量(对象)的大小,而”sizeof指针”得到的是指针本身的大小;
- 指针和引用的自增(++)运算意义不一样;
- 引用是操作受限了的指针(仅容许取内容操作)。
int i = 5;
int j = 6;
int &k = i;
k = j; // k 和i 的值都变成了6
6. 指针引用&值引用
值引用赋值
比如 a:=b,这样修改a.name=“ls”,不会影响到b.name,值引用是复制结构体,开辟一块新的内存空间,
a只是b的一个副本
,而不是指向b的引用。指针引用赋值
比如 a:=&b ,这样修改a.name=“ls”,会影响到b.name,指针引用是指向结构体内存地址的引用
,同一块内存空间
总结1:
值引用,两个变量值是独立的
,而指针引用则会互相影响
,因为他们都指向同一块内存地址。总结2:
值引用只是复制的一个副本
,不是指向内存地址的引用;指针引用,指针是指向内存地址的引用,因此使用它操作的不是结构体的副本而是本身
。总结3:
指针引用的时候,比如 b:=&a, 此时b是指针,
因此必须使用*b对其进行引用取其内容的值。