4

Go 语言没有引用类型,指针也与众不同

 2 years ago
source link: https://www.cyningsun.com/08-16-2021/go-has-no-reference-and-safe-pointer.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Go 语言没有引用类型,指针也与众不同

面向对象编程强调数据和操作绑定,方法是有状态的,本身可能会修改数据。因此编程时确定方法是否会修改原始数据尤其关键。多数从其他语言转到 Go 语言的开发者,都会首先了解 Go 语言传递参数的时候到底是 “传值” 还是 “传引用”。如果第一门开发语言是 C 语言或者 C++ 的开发者,还会区分下什么时候 “传指针”。

什么是内存?

可以把内存想想为一系列单元格,一个个排列成一行,每个单元格都有一个唯一的编号。编号顺序递增,代表内存的位置,也即是内存地址。

pointer-memory.png

每个单元格都可以存放一个值,可以通过编号读取和替换单元格内的先前写入的值。

什么是变量?

糟糕的是,如果直接使用编号编程,就需要开发者自己管理内存,也难以和其他程序同时运行,极大的增加了编写大型程序的难度。

为了解决这个问题,就需要引入“变量”的概念。变量只是编号的假名、标签或昵称。

pointer-memory-multiply.png

var a = 6
var b = a * 3

什么是指针?

而指针的值是另一个变量的编号。指针指向变量的内存地址,就像变量代表值的内存地址一样。

func main() {
        a := 200
        b := &a
        *b++
        fmt.Println(a)
}

pointer-memory-variable.png

什么是引用?

在 C++ 语言中,为现有变量声明别名,称为引用变量。如代码所示,a、b、c 三个变量均共享同一内存地址

#include <stdio.h>

int main() {
        int a = 10;
        int &b = a;
        int &c = b;

        printf("%p %p %p\n", &a, &b, &c); // 0x7ffe114f0b14 0x7ffe114f0b14 0x7ffe114f0b14
        return 0;
}

Go 语言没有引用类型

Go 程序可以创建指向统一内存地址的变量,但无法创建共享相同内存地址的两个变量。如代码所示,b 和 c 具有相同的值(a的地址)但是,b 和 c 的内存地址是唯一的。更新 b 的内容对 c 没有影响。

package main

import "fmt"

func main() {
        var a int
        var b, c = &a, &a
        fmt.Println(b, c)   // 0x1040a124 0x1040a124
        fmt.Println(&b, &c) // 0x1040c108 0x1040c110
}

2013年4月3日,“引用类型”的概念已从 Go 规范中完全删除,现在 Go 规范中的“引用”,没有一个代表“引用类型”的概念。

指针是类型吗?

指针是类型吗?这个问题可能在 C 或 C++ 中会有比较大的分歧,但是在 Go 语言中十分明确,毫无疑问:是的

A pointer type denotes the set of all pointers to variables of a given type, called the base type of the pointer. The value of an uninitialized pointer is nil.

既然有类型,就有类型的实例:值,类型和值是截然不同的两个概念。显然,在 Go 语言中,当谈到指针时,包含 “指针类型” 和 “指针值”。

同时,为了避免指针引入的风险, Go 语言对指针做了不少的约束,如下:

  1. 指针值不支持数学运算
var p *int
p++

你不能更改指针指向的位置,除非赋值另外一个地址给它。同时也就不支持 Array-Pointer Duality

  1. base type 不同的指针值,无法直接互相赋值
type MyInt int64
type Ta    *int64
type Tb    *MyInt

// 4 nil pointers of different types.
var pa0 Ta
var pa1 *int64
var pb0 Tb
var pb1 *MyInt

   // None of the following 3 lines compile ok.
/*
_ = pa0 == pb0
_ = pa1 == pb1
_ = pa0 == Tb(nil)
*/
  1. 返回局部变量的指针是安全的
func f() *int { 
  i := 1
  return &i
}

使用过 C/C++ 语言的开发者,习惯使用的不安全的指针是 unsafe.Pointer,而非普通的指针。

int* valFirst
intptr_t valSecond
void* valThird
int* valFirst
type intptr_t *int
intptr_t valSecond
unsafe.Pointer valThird

对比服用,效果更佳。

本文作者:cyningsun
本文地址https://www.cyningsun.com/08-16-2021/go-has-no-reference-and-safe-pointer.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK