Go的&*

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/fujian9544/article/details/100110011

1.值传递与引用传递形象化理解:

引用传值:相当于把烧饼串成一串,然后是有底座的,这个底座就相当于地址,这个地址对应的烧饼就相当于变量,这个地址对应的所有的变量都是一样的;

值传递:各个烧饼都是平放的,新的烧饼只是复制了之前的烧饼,之后被吃了,或者被煮了,与最开始的烧饼无关了

传地址进函数,函数内外的变量一起变化

传值进去,函数内的变化不影响函数外

2.分析两者:

2.1采用引用传值的时候:

函数内部用&:

我们希望这个地址对应的变量会随着变化 所以使用&  一般是函数内部,因为函数内部就是要变量变化的嘛。

函数内对指定变量进行赋值(这里的赋值其实是地址对应的变量的赋值,所以用&)

与return返回值的时候使用&(这里返回也是返回&{变量}))

函数声明的时候*:

因为是最终的结果  所以直接用*  不用再在乎是否变化  一般是函数的入参与返回参数

2.2采用值传递的时候:

赋值用值传递 返回值的时候也用值传递  过程中也用值传递就可以  都没有符号  

3.属性加*的理解

一般属性

因为int对应iptr,因为int是一个地址,所以iptr也是一地址;
我们传入的参数就是以地址&i;
函数里面:*iptr=*&i=0  
我们对地址(iptr &i)进行赋值的,所以变量(*iptr i)都会发生变化;
这是从根上地址发生的变化;
所以我们对属性加*的目的就很清楚了,
让函数内外的变量一起变化。

属性加*属性的话  调用的地方必定是&变量

集合属性结构体

结构体加&与不加&进行赋值修改操作没有任何影响。

package main

import "fmt"

type person struct {
	name string
	age  int
}

var a int

func main() {
	// 一般展示
	// 结构体加&赋值 &{Ann 40}
	// 结构体不加赋值 {Ann 40}
	fmt.Println("结构体加&赋值",&person{name: "Ann", age: 40})
	fmt.Println("结构体不加赋值",person{name: "Ann", age: 40})

	// 加与不加获取属性值
	// 不加&进行获取内部属性值 50
	// 加&进行获取内部属性值 50
	a :=  person{name: "Sean", age: 50}
	b := &person{name: "Sean", age: 50}
	fmt.Println("不加&进行获取内部属性值",a.age)
	fmt.Println("加&进行获取内部属性值",b.age)
	
	// 加与不加修改属性值
	// 不加&进行修改内部属性值 51
	// 加&进行修改内部属性值 51
	a.age = 51
	b.age = 51
	fmt.Println("不加&进行修改内部属性值",a.age)
	fmt.Println("加&进行修改内部属性值",b.age)
}

3.分析代码

3.1底层使用了引用传值,上层就会用引用传值

3.2底层没有用就不会使用引用传值

3.3函数调用

4.实际代码

package main
 
import(
	"fmt"
	"reflect"
)
 
type b struct{
	c int
	d string
}
 
type bb struct{
	ff b
	dd string
}
 
type bbb struct{
	// 这句话是在表明
	// c是一个引用传值
	// b对应地址
	c *b
	dd string
}
 
func main(){
	a:=1;
	// &{变量}=地址  给地址赋值哈 
	// *{地址}=值    取出地址值哈
	fmt.Println(&a);	// 0xc042052058

	fmt.Println(*&a);	// 1
	// fmt.Println(*a);//报错  错误的指向  所以说a必须是一个地址  在这个例子中 a不是地址  所以报错


	// 这个是结构体的简单引用传值与值传递
	// &{变量}-结构体的赋值先要声明哪个类型结构体
	g:=&b{c:1,d:"gggg"};
	fmt.Println(g);// &{1 gggg}

	gg:=b{c:1,d:"gggg"};
	fmt.Println(gg);// {1 gggg}

 
	// 这个是结构体嵌套结构体进行值传递
	gggg:=bb{ff:b{c:1,d:"gggg"},dd:"gggg"}
	fmt.Println(gggg);// {{1 gggg} gggg}

 
	// 这个是结构体嵌套进行引用传值  
	// 因为此时在bbb中b是一个地址&{}
	// c后面是结构体进行赋值  是对
	// 此处的b只是针对结构体b的 
    // *b  所以b为地址  所以传递地址即&b
	ggggg:=bbb{c:&b{c:1,d:"gggg"},dd:"gggg"}
	fmt.Println(reflect.TypeOf(ggggg.c));//*main.b
	fmt.Println(ggggg.c);				//&{1 gggg}
	fmt.Println(ggggg);					// {0xc04204c420 gggg}
 
	// 这个是结构体嵌套进行引用传值  
	// 这样是错误的哈,在bbb里面b是引用传值  直接用值传递会报错
	// cannot use b literal (type b) as type *b in field value
	// 不能在字段值中使用b文字(类型b)作为类型*b
	// 就是说我们用的是b类型  在结构体声明的时候是*b  所以错误
	// gggggg:=bbb{c:b{c:1,d:"gggg"},dd:"gggg"}
	// fmt.Println(gggggg);				//错误

	// invalid indirect of b literal (type b) b字母无法指向b类)
	// ggggggg:=bbb{c:*b{c:1,d:"gggg"},dd:"gggg"}
	// fmt.Println(ggggggg);			//错误

	// 结构体的定义要么是值传递(方式一)      要么是引用传递使用* 对类型定义(方式二)
	// 结构体的赋值要么是什么值传递(方式一)  要么引用传递-&类型名字{id:1,name:"aa"}(方式二)
	// 方式一对应方式一;方式二对应方式二
}
 
// 0xc042052058
// 1
// &{1 gggg}
// {1 gggg}
// {{1 gggg} gggg}
// *main.b
// &{1 gggg}
// {0xc04204c420 gggg}

5.对应

  1. // 结构体的定义要么是值传递(方式一) 要么是引用传递使用* 对类型定义(方式二)

  2. // 结构体的赋值要么是什么值传递(方式一) 要么引用传递-&类型名字{id:1,name:"aa"}(方式二)

  3. // 方式一对应方式一;方式二对应方式二

猜你喜欢

转载自blog.csdn.net/fujian9544/article/details/100110011