辨析指针与引用 | C++与Go的不同

65 阅读2分钟

前言


最近在刷题/开发过程中遇到了有关指针的问题,特来记录,希望今后不要再受指针和引用的困扰。

C++ version


1.交换两个变量的值

void swap(int *a, int *b) { 
    int tmp = *a; 
    *a = *b; 
    *b = tmp; 
}

2.交换一个数组中两个元素的值(刷题常用)

有一个这样的swap函数,考虑到与标准库的冲突,我起名为my_swap()

void my_swap(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}

这个函数是用来交换数组中两个元素的值的。

int main()
{
    int a[2] = {2, 250};
    my_swap(a[0], a[1]);
    cout << "a[0]:" << a[0] << "   a[1]:" << a[1] << endl;
    return 0;
}

a[0]:250 a[1]:2

为什么交换数组的时候,取法这么特殊?为什么int类型的变量可以赋值为int &?

引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。

一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。

想到这里,心中的疑惑就差不多烟消云散了。

int temp = a;,我们可以cout出来试一下。

image.png

image.png

他并没有打印一个地址,而是就打印的值。引用可以初始化为某个变量,并且通过改变引用的方式改变地址,进而改变值。

Go version


Go语言的交换变量就没有这么麻烦了。

a[i], a[j] = a[j], a[i]即可。Go的元组赋值法会让一切简单起来。

新的问题又出现了,观察到Go语言的项目中用了很多指针,并且传入参数也是传入指针,传入指针的意义何在?

我在查找问题答案的过程中,发现这样一篇专栏:Go只有值传递?

分析与举例

Example 1

假设现在有一个user实例对象,我们要在数据库中查找/创建这条记录。

db.Create(&user)或者db.Find(&user, 1)传入的都是这个实例对象的引用。

传引用就相当于传入他的地址。

如果传入的就是原本的值,函数调用时,实参通过拷贝将自身内容传递给形参,形参实际上是实参值的一个拷贝。此时,针对函数中形参的任何操作,仅仅是针对实参的副本,不影响原始值的内容。所以才有了传入地址的概念。

Example 2

type user struct {
	Name string
	Age  int8
}

man := user{Name: "sb"}
man.Age = 20
fmt.Println(man.Age)

20

如果改为:

man := &user{Name: "sb"}
man.Age = 20
fmt.Println(man.Age)

20

都是一样的,一个实例对象能访问的成员,他的指针一样能访问。

但是如果是函数传参,可能就不会在函数内改变它的值了。此处不再附上代码。