您的位置 首页 golang

Golang之指针

写在前面:

0x01 — 取址符和取值符

指针定义和获取在前面的文章中已经提及,在这里明确讲解下使用方法,获取一个变量的指针可以通过&符号获取:

 package main

import (
   "reflect"
   "testing"
)

func TestPointer(t *testing.T) {
   // 定义一个变量a
   a := 10
   // 获取的指针
   b := &a
   c := b
   t.Log("a的值",a)
   t.Log("b的值",b)
   t.Log("c的值",c) // 指针可以被传递
   t.Logf("b的类型%T",b) //通过格式化字符串%T可以打印对象的类型

   // 通过反射也可以打印对象类型,格式化字符串的原理也是反射,关于反射后面会专门说明
   t.Log("b的类型",reflect.TypeOf(b))
}  

输出:

 === RUN   TestPointer
    pointer_test.go:14: a的值 10
    pointer_test.go:15: b的值 0xc00001c320
    pointer_test.go:16: c的值 0xc00001c320
    pointer_test.go:17: b的类型*int
    pointer_test.go:20: b的类型 *int
--- PASS: TestPointer (0.00s)
PASS  

通过&符号可以获取a的指针,指针的类型是int型,在类型前面标记一个*号,表示此对象是一个指针,指针可以传递,指针指向的地址内容变化,所有指向此内存的指针内容将发生变化,指针无变化。

通过指针我们可以获取指针指向地址的数据,符号是*, 方法如下:

 package main

import (
   "reflect"
   "testing"
)
func TestPointerGet(t *testing.T) {
   // 定义一个变量a
   a := 10
   // 获取的指针
   b := &a
   t.Log("a的值",a)
   t.Log("b的值",b)
   c := *b
   t.Log("c的值", c)
   a = 20
   t.Log("c的值", c)
   t.Log("b的值", b)
   t.Log("*b的值", *b)
}  

输出:

 === RUN   TestPointerGet
    pointer_test.go:15: a的值 10
    pointer_test.go:16: b的值 0xc0001281e8
    pointer_test.go:18: c的值 10
    pointer_test.go:20: c的值 10
    pointer_test.go:21: b的值 0xc0001281e8
    pointer_test.go:22: *b的值 20
--- PASS: TestPointerGet (0.00s)
PASS将*b赋值给c,这一步其实是复制,会重新分配一个内存空间,可以看到c的指针和b是不同的,我们在修改a的值得时候,改的是指针b指向的内存空间的值,所以*b会被同时修改,而c是不会变化的。

0x02 -- 定义指针
除了上面我们通过取址符获取指针外,我们还可以自己定义指针:  

将*b赋值给c,这一步其实是复制,会重新分配一个内存空间,可以看到c的指针和b是不同的,我们在修改a的值的时候,改的是指针b指向的内存空间的值,所以*b会被同时修改,而c是不会变化的。

0x02 — 定义指针

除了上面我们通过取址符获取指针外,我们还可以自己定义指针:

 package main

import (
   "reflect"
   "testing"
)

func TestPointerDefine(t *testing.T) {
   var a *int
   var b * float64
   var ta int = 10
   a = &ta
   // 下面两行代码会报错:Cannot use '&tb' (type *float32) as the type *float64
   // 定义的指针类型和赋值的指针类型必须相同,不可隐身转换
   //var tb float32 = 20.1
   //b = &tb
   var tb float64 = 20.1
   b = &tb
   t.Log("a的值:", a)
   t.Log("b的值:", b)

   // 定义空指针
   var c * int
   t.Log("c的值:", c)
   t.Log("是否为空指针:", c == nil)
}  

输出:

 === RUN   TestPointerDefine
    pointer_test.go:19: a的值: 0xc0000a2210
    pointer_test.go:20: b的值: 0xc0000a2218
    pointer_test.go:24: c的值: <nil>
    pointer_test.go:25: 是否为空指针: true
--- PASS: TestPointerDefine (0.00s)
PASS  

空指针默认值是0,地址指向为nil,可以与nil比较确认是否为空指针。

0x02 — 总结

指针很简单,只需要明确指针本身和指针指向两个概念就可以,比如指向指针的指针也是可以的。变量存储的内容是指针或者是内容数据不影响变量的本质。在写go代码时,经常会考虑,我应该使用值类型还是指针类型?如以下几种情况,该如何决定:

  • 一个局部变量赋值
  • 结构体字段
  • 函数返回值
  • 传递给函数的参数
  • 方法的接收者

如果你不确定使用那个,那么就使用指针。

知道自己写的代码想要干什么是很重要的,传递值类型是一种确保数据不可变的好方法,可有效防止数据在处理中被改变,尤其是有并发的情况,有些时候,这很必要,但是更多时候,可能真不需要,值传递会造成很大的内存空间占用,尤其是针对体积很大的结构体,如果本身数据量特别小,那么随便哪个都可以,不要再这样的问题上花费太多时间,优选指针。

文章来源:智云一二三科技

文章标题:Golang之指针

文章地址:https://www.zhihuclub.com/86781.shtml

关于作者: 智云科技

热门文章

网站地图