go基础系列 第二章 go函数和指针
Posted itpower
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go基础系列 第二章 go函数和指针相关的知识,希望对你有一定的参考价值。
1. 函数
2.指针
一. 函数
二. 指针
先来看一段代码
var a int =2 var pa *int pa = &a *pa = 3 fmt.Println(a)
这里定义了一个int类型的变量a, 有定义了一个指针类型的变量pa, 让pa指向了a的地址. 然后修改了pa的值, 我们看看打印出来的a是什么:
结果: 3
下面开始描述指针
1. 指针也是一种变量, 指针变量的定义方式, 和普通变量的定义方式一样
2. go语言中的指针不能进行运算. 在c中,指针是可以运算的. 比如 &pa+2, 这在go中是不可以的. 还是刚才的例子,我们对指针进行运算, 编译就过不去
3. go语言只有值传递, 没有引用传递. 如何实现go语言的引用传递呢, 配合指针.
如果你想要传递一个int类型的数值,如果是直接传递过去. 那么就是值拷贝. 如果想要引用传递, 那么就要把指针传递过去.
问题: 对象是值传递还是引用传递呢?
答案: 不一定. 如果你将一个对象Cache传递到一个函数里. 他是对这个Cache的一值copy么? 不一定. 要看这个函数里面的内部结构: 看下面的例子.
例子1:
type Cache struct { aa int bb int cc string } func change(c Cache) { c.cc = "world" fmt.Println("in change, c", c) } func main() { // 初始化一个Cache对象 var c = Cache{aa:1, bb:100, cc:"hello"} // 修改对象的值. 这里传递过去的是一个值拷贝 change(c) fmt.Println(c) }
这个例子, 就是对象的一个值拷贝的过程. 修改了函数体里面对象的属性, 对函数外没有影响,
结果:
in change, c {1 100 world} {1 100 hello}
例子2:
type Cache struct { aa int bb int cc string } func change(c *Cache) { c.cc = "world" fmt.Println("in change, c", c) } func main() { // 初始化一个Cache对象 var c = Cache{aa:1, bb:100, cc:"hello"} // 修改对象的值. 这里传递过去的是一个值拷贝 change(&c) fmt.Println(c) }
这个例子和例1不一样的地方是, 函数的参数是一个指针. 这就是引用传递, 修改函数体里面的值,外面也受影响.
返回结果:
in change, c &{1 100 world} {1 100 world}
例子3:
type Cache struct { aa int bb int cc *string } func change(c Cache) { *c.cc = "world" fmt.Println("in change, c", c.aa, c.bb, *c.cc) } func main() { // 初始化一个Cache对象 cc := "hello" var c = Cache{aa:1, bb:100, cc:&cc} // 修改对象的值. 这里传递过去的是一个值拷贝 change(c) fmt.Println(c.aa, c.bb, *c.cc) }
例子3: 和前两个例子不同的地方时, 结构体Cache中cc是一个地址. 他不是一个变量了. 那么这个时候. change函数修改了cc的值,会怎么样呢?
结果:
in change, c 1 100 world 1 100 world
是的, cc是一个引用传递, 函数内改变了cc所在地址的值, 那么函数外也会改变
这就说明了, 结果体传递到函数里面, 到底是值传递还是引用传递呢? 和结构体内部的结构有关系.
3. 用go语言实现交换两个变量的值.
错误方法:
type Cache struct {
aa int
bb int
cc *string
}
func change(a int ,b int) {
a, b = b, a
fmt.Println("in change, a:", a, ", b:", b)
}
func main() {
// 初始化一个Cache对象
a, b := 3, 4
change(a, b)
fmt.Println(a, b)
}
上述方法返回值:
in change, a: 4 , b: 3
3 4
错误的原因在于, int类型是值传递, 修改内容的值, 对外部没影响. 所以返回的还是3, 4
案例3: 使用指针
func change(a *int ,b *int) {
fmt.Println(fmt.Println("[change---1], a:", a, ", b:", b))
a, b = b, a
fmt.Println("[change--2], a:", a, ", b:", b)
}
func main() {
// 初始化一个Cache对象
a, b := 3, 4
fmt.Println("[main --- 1]", &a, &b)
change(&a, &b)
fmt.Println("[main --- 2]", a, b)
}
先来看输出结果:
[main --- 1] 0xc000096008 0xc000096010
[change---1], a: 0xc000096008 , b: 0xc000096010
48 <nil>
[change--2], a: 0xc000096010 , b: 0xc000096008
[main --- 2] 3 4
出乎意料, 原本以为, main函数最后的输出会是4, 3. 我们发现, 结果并不是. 也就是说, 虽然传的是指针过去, 但是是对指针的一个copy, 这一点更说明了, 所有的变量都是值拷贝. 包括指针变量. 也是一个值拷贝
案例4: 地址传递
func change(a *int ,b *int) { fmt.Println(fmt.Println("[change---1], a:", a, ", b:", b)) *a, *b = *b, *a fmt.Println("[change--2], a:", a, ", b:", b) } func main() { // 初始化一个Cache对象 a, b := 3, 4 fmt.Println("[main --- 1]", &a, &b) change(&a, &b) fmt.Println("[main --- 2]", a, b) }
案例4和三个不同之处, 是在change函数内, 修改了指针类型的变量的值. 输出结果是:
[main --- 1] 0xc00001c0f8 0xc00001c100 [change---1], a: 0xc00001c0f8 , b: 0xc00001c100 48 <nil> [change--2], a: 0xc00001c0f8 , b: 0xc00001c100 [main --- 2] 4 3
我们看到, 最后的输出结果却是是4, 3
从这里我们得出以下结论:
1. 指针类型的变量, 和普通变量一样, 是值传递.
2. 指针类型的变量, 要向修改变量的值, 需要使用指针的指针来改变. 其实,在指针里面, 是指针的指针就是值了. 那么, 我们的原则是, 不管他是什么, 只有修改的是指针, 那么就是地址传递.
例子5: 还有一种更简单的交换两个值的方式
func change(a *int ,b *int) (int, int){ return *b, *a } func main() { // 初始化一个Cache对象 a, b := 3, 4 fmt.Println("[main --- 1]", &a, &b) a,b = change(&a, &b) fmt.Println("[main --- 2]", a, b) }
输出:
[main --- 1] 0xc00001c0f8 0xc00001c100 [main --- 2] 4 3
案例6: 最简单的方式
func change(a int ,b int) (int, int){ return b, a } func main() { // 初始化一个Cache对象 a, b := 3, 4 fmt.Println("[main --- 1]", &a, &b) a,b = change(a, b) fmt.Println("[main --- 2]", a, b) }
结果:
[main --- 1] 0xc000096008 0xc000096010 [main --- 2] 4 3
指针对于我们来说, 方便好多, 但是也会产生很对疑问. 比如案例5和案例6, 他们为什么得到的结果是一只呢?需要分析原因.
aaa
以上是关于go基础系列 第二章 go函数和指针的主要内容,如果未能解决你的问题,请参考以下文章