乐趣区

关于后端:看完这个我彻底了解了golang的指针

golang 中一个十分显明的特点就是引入了指针的应用,这个在 py、php、java 中都是不反对的,然而很多读者都反馈说对指针不是很理解,所以明天写了这篇文章,当然我尽量用艰深的语言,心愿对您有用。

什么是指针

想理解什么是指针,你先得理解数据是怎么取到的

func main() {
    var a int
    a = 1
    fmt.Println("a 的值为", a)
}

上述代码非常简单,我置信不会 golang 的读者应该也能看懂。然而他底层到底干嘛了?你真的理解过么?接下来咱们逐个解释

var a int

首先这一步,是给变量 a,在内存中开拓了一块空间,因为是 int 类型,所以空间大小为 4 个字节,那么问题来了,这块空间开在内存哪个地位? 首先这块地位是零碎 随机调配 的一块。另外给这块内存做了一个 标记 ,不便下次找到, 这个标记就在这块内存的起始的地位

a = 1

接下来给变量 a 赋值为 1。那么零碎如何赋值的呢?首先总得找到 a 这块内存在哪吧?如何找到给 a 调配的那块内存的呢?当然是通过之前给 a 变量做的那个 标记。通过标记找到这块内存所在的地位,而后间接在开拓好的内存空间存下给 a 赋值的数据就能够了。

fmt.Println("a 的值为", a)

这段代码,咱们暂且先不必去理解 fmt.Println 是怎么实现的,只用关怀 a 是怎么取到的,当然是先 找到 a 之前所做的那个标记,找到对应的内存所在的地位,间接往后偏移 4 个地位把值取出来就行。

这下是不是感觉清晰明了了?

咱们在上述过程中,所说的 标记 ,就是 指针 . 所以指针其实就是一个 标记数据所在位置的数据类型而已, 只不过他有一些本人非凡的语法而已,而且是一种新的数据类型。这么来看,就很简略了。

指针的定义

指针是一种 数据类型 ,用于示意数据的 内存地址

如何应用指针

咱们来看上面几个例子感受一下

case1

var a string  // 申明一个字符串类型的变量,初始值为 ""
var b *string // 申明一个字符串指针类型的变量,初始值为 nil,申明指针类
fmt.Println("a:", a, "b:", b)
// 输入后果为 
//a:   b: <nil>
留神:
  • 申明指针的类型,只须要在后面加上一个 * 就能够了,这是固定的语法
  • 不论什么指针类型(int, string, *float),初始值都为 nil

    case2

    var name string = "小饭"   // 申明一个 name 为 string 类型,并且赋值为 "小饭"
    var p_name *string = &name // 申明一个 p_name 为 *string(字符串的指针类型),并且赋值为 &a(在 a 后面加上一个 & 的意思是取 a 的首地址)
    fmt.Println("name:", name, "name 的内存地址", &name, "p_name:", p_name, "p_name 的具体值:", *p_name)
    // 输入后果为 
    //name: 小饭 name 的内存地址 0x14000010240  p_name: 0x14000010240 p_name 的具体值: 小饭
    留神
  • 取变量 name 的首地址,也就是指针的值,须要用 &name 示意,而取出来的值也只能用指针这种变量类型来保留,所以 var p_name *string = &name 这段代码是正当的
  • p_name 的具体值是随机调配的一个 16 进制的值,0x14000010240,晓得这个代表的是指针的值就行了,因为是随机调配的,所以不同设施是不一样的。
  • 要取一个指针类型指向的具体值,用 (对应的指针类型的变量名)就能间接取到, 比方下面的例子,对应的指针类型的变量名为 p_name,所以用p_name 就能间接取到指针 p_name 所指向的具体值。

    阐明

    下面咱们通过 &name 获取到了 name 的内存空间的地址是 0x14000010240,p_name 的变量的值实际上是 name 变量的内存空间的值,p_name 也是一个变量
    那么 p_name 变量所寄存值的中央,是不是也会有一个内存空间呢?是的,p_name 这个指针变量也会指向一个内存空间

var name string = "小饭"
    var p_name *string = &name

    fmt.Println("name:", name, "p_name 的值", p_name, "p_name 指针变量的内存地址:", &p_name)
  // 输入
  //name: 小饭 p_name 的值 0x14000010240  p_name 指针变量的内存地址: 0x1400000e028

指针在数组中的利用

大家首先得辨别一个概念,数组指针 指针数组 的区别。

数组指针

简略说数组指针就是整个数组都为指针

  a, b, c := 1, 2, 3
    arr := [3]int{a, b, c}
    var ptrArr *[3]int  
    ptrArr = &arr
    arr[1] = 200   // 扭转数组的值,并不会影响到对应数组元素的变量自身
    fmt.Println(b)
    fmt.Println(arr[1])
    fmt.Println((*ptrArr)[1]) // 能够简略写为:ptrArr[1]
  // 后果输入为
  //2
  //200
  //200
间接扭转数组的某个元素,不会影响到对应元素的变量。

指针数组

简略说就是数组每个元素都为指针

  a, b, c := 1, 2, 3
    arr := [3]int{a, b, c}
    arr[1] = 2 // 批改一般数组中的值
    // 定义指针数组
    var ptrArr [3]*int  // 每个元素为一个指针
    ptrArr = [3]*int{&a, &b, &c}
    *ptrArr[1] = 200 // 批改某个元素的指,不会影响到数组自身
    fmt.Println(b)
    fmt.Println(arr[1])
    fmt.Println(*ptrArr[1])
  // 后果输入
  //200
  //2
  //200

当然指针数组和数组指针有很多细节须要留神,如果这篇文章浏览量还能够,咱们前面专门会开一篇解说这个问题。在这里有个简略的意识即可。心愿大家记得多多转发和点赞哦。

指针在函数中的利用

case1

func main() {
    var a int = 123
    changeData(a)
    fmt.Println(a)
}
func changeData(b int) {b = 456}
// 输入后果
//123

大家设想一下最终打印进去的 a 是 123 还是 456,当然是 123. 为什么会这样呢?因为运行到 changeData 中,把 a 传进去之后,相当于执行了一步

var b int
b = 1

所以天然对 b 进行任何批改都不会影响到 a,输入的天然是 123

case2

func main() {
    var a int = 123
    changeData(&a)
    fmt.Println(a)
}
func changeData(b *int) {*b = 456}

在这一次函数参数传递中,相当于执行了

var b *int
b = &a

b 就是指向 a 的指针,所以 * b 批改了,a 天然也会跟着批改。

golang 指针和 c 语言指针的区别

大家晓得 C 语言之所以弱小,就是因为 c 语言反对指针,而且权限特地大,c 语言能够对计算机中任何内存的指针进行操作,这样自然而然也会带来一些不平安的因素,所以在 golang 中,勾销了对指针的一些偏移,翻转等算术运算 (+、-、++、–) 所以应用起来更平安。

本文由 mdnice 多平台公布

退出移动版