专栏名称: 狗厂
目录
相关文章推荐
51好读  ›  专栏  ›  狗厂

Golang | 我对变量产生了这些想法

狗厂  · 掘金  ·  · 2018-06-04 02:57

正文

最近在学习Golang的过程中,发现一个有意思的事情,有的文章说函数调用传参时 slice 是引用传递,有的说是值传递。为什么同一个东西大家会不同认识?为了搞清楚其本质,我进行了以下内容的研究:

  1. 变量的变量名、变量值、变量地址在内存中是怎么样的?

  2. 指针的定义是什么?引用的定义是什么?二者有什么关系?

  3. 函数传参中值传递、指针传递与引用传递到底有什么不一样?

  4. Go中 slice 在传入函数时到底是不是引用传递?如果不是,在函数内为什么能修改其值?

为了避免文章写的过长,看了想瞌睡,分成两篇文章来解释这个问题,本文先解决问题1跟2,下一篇说明余下的问题。

变量名:程序员给地址取的外号

上学的时候,老师讲变量是存在内存中的,内存就像一排排抽屉组成的,每个抽屉上面有个编号,我们定义一个变量,就是把想放的东西放到这个对应编号的抽屉里。比如: int a = 10,用图来表示下:

这里:变量的名字叫 a ,变量的值是: 10 ,变量的地址是: 0x 00000001 。那么问题来了,变量的值我们知道是放在了抽屉里(内存中),每个抽屉有编号(地址),但是变量的名字 a 存放在哪里呢?或者说它会存在于内存中吗?

大家想一个问题,如果变量的名字要存放在内存中,那么肯定分配一个空间给它,保存它的空间有个地址,这个地址是不是又得有个地方存起来程序才能找到?如果真是这样设计,那么代码根本没发写、无法运行了。

其实变量名仅仅是写给程序员看的,让我们写代码的时候知道这个变量有什么用,能够通过名字调用变量的值。因为如果直接给你一个地址 0x 23004123,你知道这是要干嘛吗?代码经过编译后,最终都会转换成机器码,我们定义的变量名就都不存在了,存在的只有地址跟值。

指针其实很普通

有了上面的理解,再来一个特殊的变量:指针变量。什么叫指针变量呢?其实就是这个变量里边存放的是一个变量的地址,通过这个地址,机器可以找到对应变量的值,例如:int * pa = &a,就表示变量 pa 抽屉里放的是 a 的地址,它的类型是:int*,继续看图:

这里需要重要说明的是:指针pa与a的关系是:a抽屉里边放的是变量值10,pa放的是变量的地址:0x00000001 ,这里一定要记住,下面说引用的时候才更容易理解。

引用就是变量的另一名字

继续谈引用,引用与指针我们经常傻傻分不清,因为它们的行为确实非常诡异,看起来效果非常相似,看代码:

由于引用的概念是在 c++ 中引入的,因此下面的代码使用c++,仅仅是一些打印而已,放心看下去

int main() {    int a = 10;// 变量
    int * pa = &a; // 指针
    int & b = a; // 引用

    printf("a: %d\n", a);// a: 10
    printf("*pa: %d\n", *pa);// *pa: 10
    printf("b: %d\n", b);// b: 10

    *pa = 20;    printf("a: %d\n", a);// a: 20
    printf("*pa: %d\n", *pa);// *pa: 20
    printf("b: %d\n", b);// b: 20

    b = 30;    printf("a: %d\n", a);// a: 30
    printf("*pa: %d\n", *pa);// *pa: 30
    printf("b: %d\n", b);// b: 30

    a = 40;    printf("a: %d\n", a);// a: 40
    printf("*pa: %d\n", *pa);// *pa: 40
    printf("b: %d\n", b);// b: 40
    return 0;
}

通过上面的代码我们发现,指针与引用都能达到一个效果:都有能力修改a的值,指针前面讲过了,因为它保存了a的地址,通过解引用操作后,实际上就是打开了a的抽屉,因此可以进行修改。那么引用又是怎么办到的?这里注意一个细节:*pa = 20; c = 30;a = 40。我们看到操作c的时候与操作a是一样的方式:直接使用变量名,但是pa要想改变a的值,必须进行 *pa 操作(解引用),如果直接 pa=20,这仅仅是改变的pa的值,让他指向了另外一个地址。







请到「今天看啥」查看全文