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

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

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

概念

什么是内存?

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

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

什么是变量?

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

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

var a = 6
var b = a * 3

什么是指针?

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

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

什么是引用?

在 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

vs

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 许可协议。转载请注明出处!

# Golang

  1. 译|There Are No Reference Types in Go
  2. 译|What “accept interfaces, return structs” means in Go
  3. 如何用好 Go interface
  4. 一个优雅的 LRU 缓存实现
  5. Go 函数式编程:Higher-order function
目录
相关文章
|
5天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
23 2
|
3天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
11 2
|
3天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
14 2
|
6天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
3天前
|
Go
go语言中的 跳转语句
【11月更文挑战第4天】
10 4
|
3天前
|
JSON 安全 Go
Go语言中使用JWT鉴权、Token刷新完整示例,拿去直接用!
本文介绍了如何在 Go 语言中使用 Gin 框架实现 JWT 用户认证和安全保护。JWT(JSON Web Token)是一种轻量、高效的认证与授权解决方案,特别适合微服务架构。文章详细讲解了 JWT 的基本概念、结构以及如何在 Gin 中生成、解析和刷新 JWT。通过示例代码,展示了如何在实际项目中应用 JWT,确保用户身份验证和数据安全。完整代码可在 GitHub 仓库中查看。
14 1
|
5天前
|
Go 调度 开发者
探索Go语言中的并发模式:goroutine与channel
在本文中,我们将深入探讨Go语言中的核心并发特性——goroutine和channel。不同于传统的并发模型,Go语言的并发机制以其简洁性和高效性著称。本文将通过实际代码示例,展示如何利用goroutine实现轻量级的并发执行,以及如何通过channel安全地在goroutine之间传递数据。摘要部分将概述这些概念,并提示读者本文将提供哪些具体的技术洞见。
|
1月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
22 0
|
2月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
3月前
|
C语言
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)