go语言中指针的使用场景?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言中指针的使用场景?相关的知识,希望对你有一定的参考价值。

如果该函数会修改receiver,此时一定要用指针
如果receiver是 struct 并且包含互斥类型 sync.Mutex ,或者是类似的同步变量,receiver必须是指针,这样可以避免对象拷贝
如果receiver是较大的 struct 或者 array ,使用指针则更加高效。多大才算大?假设struct内所有成员都要作为函数变量传进去,如果觉得这时数据太多,就是struct太大
如果receiver是 struct , array 或者 slice ,并且其中某个element指向了某个可变量,则这个时候receiver选指针会使代码的意图更加明显
如果receiver使较小的 struct 或者 array ,并且其变量都是些不变量、常量,例如 time.Time ,value receiver更加适合,因为value receiver可以减少需要回收的垃圾量。
参考技术A 如果该函数会修改receiver,此时一定要用指针
如果receiver是 struct 并且包含互斥类型 sync.Mutex ,或者是类似的同步变量,receiver必须是指针,这样可以避免对象拷贝
如果receiver是较大的 struct 或者 array ,使用指针则更加高效。多大才算大?假设struct内所有成员都要作为函数变量传进去,如果觉得这时数据太多,就是struct太大
如果receiver是 struct , array 或者 slice ,并且其中某个element指向了某个可变量,则这个时候receiver选指针会使代码的意图更加明显
如果receiver使较小的 struct 或者 array ,并且其变量都是些不变量、常量,例如 time.Time ,value receiver更加适合,因为value receiver可以减少需要回收的垃圾量。

Go指针

Go 语言指针

Go 语言中指针是很容易学习的,Go 语言中使用指针可以更简单的执行一些任务。

接下来让我们来一步步学习 Go 语言指针。

我们都知道,变量是一种使用方便的占位符,用于引用计算机内存地址。

Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。

以下实例演示了变量在内存中地址:

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main(){
 8     var name string
 9     name = "demon"
10     fmt.Println("name变量的指针地址:",&name)
11 }

以上代码运行返回的结果:

name变量的指针地址: 0xc420076050

什么是指针

一个指针变量可以指向任何一个值的内存地址它指向那个值的内存地址。

类似于变量和常量,在使用指针前你需要声明指针。指针声明格式如下:

var var_name(变量名) *var_name_type(数据类型)

var_name就是变量的名称,var_name_type是指针的数据类型,*用于指定变量是一个指针,例如以下的指针声明

var name *string            //指向字符串类型的指针
var age  *int                //指向整数型类型的指针

如何使用指针

指针使用流程:

  • 定义指针变量。
  • 为指针变量赋值。
  • 访问指针变量中指向地址的值。

在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 
 8 func main(){
 9     //定义局部变量num1 num2
10     var num1 int = 50
11     var num2 *int
12 
13     //获取num1变量的内存地址并赋值给num2变量
14     num2 = &num1
15 
16     fmt.Println("num1变量的内存地址为:", &num1)
17     fmt.Println("num2变量指针的地址为:", num2)
18 
19     //获取变量num1的值
20     fmt.Println("num1变量的值为:", num1)
21     //获取变量num2的值
22     fmt.Println("num2变量的值为:", *num2)
23 
24 }

以上代码返回的运行结果:

num1变量的内存地址为: 0xc42006e178
num2变量指针的地址为: 0xc42006e178
num1变量的值为: 50
num2变量的值为: 50

Go 空指针

当一个指针被定义后没有分配到任何变量时,它的值为 nil。

nil 指针也称为空指针。

nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。

一个指针变量通常缩写为 ptr。

查看以下实例:

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main(){
 8     //初始化局部变量 ptr s 分别都是空指针
 9     var ptr  *int
10     var s      *string
11     //初始化局部变量num1 num2,因为num1赋值了并且num2的指针指向了num1
12     var num1 float32 = 50.123
13     var num2 *float32
14     num2 = &num1
15 
16     //分别输出变量的值
17     fmt.Printf("ptr的空指针的值为:%v\n", ptr)
18     fmt.Printf("s的空指针的值为:%v\n", s)
19     fmt.Printf("num2的值为%v\n", *num2)
20 
21     //做判断,如果是空指针的话值就是nil
22     if ptr == nil{
23         fmt.Println("ptr是空指针哦~")
24     }
25 
26     if s == nil{
27         fmt.Println("s是空指针哦~")
28     }
29 
30     if num2 == nil{
31         fmt.Println("num2的是空指针哦~")
32     }else {
33         fmt.Println("num2的值为:", *num2)
34     }
35 
36 }

以上代码返回的运行结果:

ptr的空指针的值为:<nil>
s的空指针的值为:<nil>
num2的值为50.123
ptr是空指针哦~
s是空指针哦~
num2的值为: 50.123

Go 语言指针数组

number为整型指针数组。因此每个元素都指向了一个值。以下实例的三个整数将存储在指针数组中:

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main(){
 8     //定义一个blance数组,并且拥有五个元素
 9     var blance = [5] int {1,2,3,4,5}
10     //定义常量MAX为5
11     const MAX int =  5
12     //定义数组指针number
13     var number [MAX] *int
14 
15     for i := 0; i< MAX; i++{
16         //分别给number的数组中的每个索引赋值,值是引用blance数组中的每个元素的内存地址
17         number[i] = &blance[i]
18         fmt.Printf("blance[%d] = %d \n", i, blance[i])
19     }
20 
21     fmt.Println("----------------------")
22 
23     for i := 0; i< MAX; i++{
24         fmt.Printf("number[%d] = %d \n", i, *number[i])
25     }
26 
27     fmt.Println("----------------------")
28 
29     for i := 0; i< MAX; i++{
30         //如果blance数组与number数组一样,并且里面只的内存地址都一样,则打印两个数组元素的内存地址
31         if blance[i] == *number[i] && &blance[i] == number[i]{
32             fmt.Printf("blance[%d] %v   number[%d]  %v \n",i , &blance[i], i ,number[i])
33 
34         }
35     }
36 }

以上代码返回的运行结果:

blance[0] = 1 
blance[1] = 2 
blance[2] = 3 
blance[3] = 4 
blance[4] = 5 
----------------------
number[0] = 1 
number[1] = 2 
number[2] = 3 
number[3] = 4 
number[4] = 5 
----------------------
blance[0] 0xc4200141e0   number[0]  0xc4200141e0 
blance[1] 0xc4200141e8   number[1]  0xc4200141e8 
blance[2] 0xc4200141f0   number[2]  0xc4200141f0 
blance[3] 0xc4200141f8   number[3]  0xc4200141f8 
blance[4] 0xc420014200   number[4]  0xc420014200 

来来来来,用Python来嘲讽一波golang的数组引用赋值~

 

 1 #!/usr/bin/env python3
 2 # _*_coding:utf-8_*_
 3 
 4 __author__ = demon
 5 
 6 #声明列表l1
 7 l1 = [demon,18,beijing,"python","golang","linux"]
 8 #浅拷贝列表l1中的每个元素
 9 l2 = l1[:]
10 
11 l1_len = len(l1)
12 
13 for i in range(l1_len):
14     #判断列表中每个元素的内存地址是否一致
15     if id(l1[i]) == id(l2[i]):
16         #打印两个列表中给的每个元素及内存地址
17         print("l1[{}]   {:10}   l2[{}]  {:10} at {memory}".format(i,l1[i],i,l2[i],memory=id(l1[i])))

以上代码返回的运行结果:

l1[0]   demon        l2[0]  demon      at 4302152624
l1[1]   18           l2[1]  18         at 4330894536
l1[2]   beijing      l2[2]  beijing    at 4330894200
l1[3]   python       l2[3]  python     at 4329981408
l1[4]   golang       l2[4]  golang     at 4330894984
l1[5]   linux        l2[5]  linux      at 4329974728

Go 语言指向指针的指针

如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。

当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址:

技术分享

指向指针的指针变量声明格式如下:

var ptr **int;

以上指向指针的指针变量为整型。

访问指向指针的指针变量值需要使用两个 * 号,如下所示:

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8 
 9     var a int
10     var ptr *int
11     var pptr **int
12 
13     a = 3000
14 
15     //指针ptr地址
16     ptr = &a
17 
18     //指向指针ptr地址
19     pptr = &ptr
20 
21     //*获取pptr的值
22     fmt.Printf("变量 a = %d\n", a )
23     fmt.Printf("指针变量 *ptr = %d\n", *ptr )
24     fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)
25 }

以上代码返回的运行结果:

变量 a = 3000
指针变量 *ptr = 3000
指向指针的指针变量 **pptr = 3000

Go 语言指针作为函数参数

Go 语言允许向函数传递指针,只需要在函数定义的参数上设置为指针类型即可。

以下实例演示了如何向函数传递指针,并在函数调用后修改函数内的值:

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 //可以接收指针作为参数的自定义函数
 8 func person(name *string,age *int) string {
 9     //修改指针指向的name变量的值,影响了name的值
10     *name = "大佬"
11     fmt.Println("person函数内部的name的内存地址:", name)
12     fmt.Printf("person函数内部的修改后name变量值:%s", *name)
13     return  ""
14 
15 }
16 
17 func swap(x ,y int) string{
18     //修改x,y的值,x,y作为局部变量传递进来,因为没有使用指针,所以不会影响函数外部的x,y变量值
19     x, y = 50,100
20     fmt.Println("swap函数内部的x变量值:", x)
21     fmt.Println("swap函数内部的y变量值:", y)
22     return ""
23 }
24 
25 func main() {
26     //初始化局部变量
27     var name string = "demon"
28     var    age     int = 18
29     var x int = 10
30     var y int = 20
31 
32     fmt.Println("person函数内部的修改后name变量值:", name)
33     fmt.Println("person函数外部的name的内存地址:", &name)
34     fmt.Println(person(&name, &age))
35     fmt.Printf("person函数外部的修改后name变量值:%s \n",name)
36 
37     fmt.Println("--------------------------------------------")
38     fmt.Println(swap(x,y ))
39     fmt.Println("swap函数外部的x变量值:", x)
40     fmt.Println("swap函数外部的y变量值:", y)
41 
42 }

以上代码返回的运行结果:

person函数内部的修改后name变量值: demon
person函数外部的name的内存地址: 0xc42006e1a0
person函数内部的name的内存地址: 0xc42006e1a0
person函数内部的修改后name变量值:大佬
person函数外部的修改后name变量值:大佬 
--------------------------------------------
swap函数内部的x变量值: 50
swap函数内部的y变量值: 100

swap函数外部的x变量值: 10
swap函数外部的y变量值: 20

 

以上是关于go语言中指针的使用场景?的主要内容,如果未能解决你的问题,请参考以下文章

Go语言并发的设计模式和应用场景

Go语言切片

C语言面试中的问题-指针和引用的使用场景?

C 语言指针间接赋值 ( 间接赋值三要素 | 间接赋值 使用的三种场景 )

Go语言之panic和recover

go(golang)中的类型转换