小编典典

在 Go 中使用指针有什么意义?

go

我知道 Go 中的指针允许改变函数的参数,但如果它们只采用引用(使用适当的 const 或可变限定符),它会不会更简单。现在我们有指针和一些内置类型,如映射和通道隐式按引用传递。

我是不是遗漏了什么,或者 Go 中的指针只是一个不必要的并发症?


阅读 479

收藏
2021-11-25

共1个答案

小编典典

指针之所以有用,有几个原因。指针允许控制内存布局(影响 CPU 缓存的效率)。在 Go 中,我们可以定义一个结构,其中所有成员都在连续内存中:

type Point struct {
  x, y int
}

type LineSegment struct {
  source, destination Point
}

在这种情况下,Point结构嵌入在LineSegment结构中。但是您不能总是直接嵌入数据。如果要支持二叉树或链表等结构,则需要支持某种指针。

type TreeNode {
  value int
  left  *TreeNode
  right *TreeNode
}

Java、Python 等没有这个问题,因为它不允许你嵌入复合类型,所以不需要在语法上区分嵌入和指向。

使用 Go 指针解决的 Swift/C# 结构问题

实现相同目的的一种可能替代方法是区分C# 和 Swiftstructclass按照 C# 和 Swift 的方式进行区分。但这确实有局限性。虽然您通常可以指定函数将结构作为inout参数来避免复制结构,但它不允许您存储对结构的引用(指针)。这意味着当您发现结构体对于创建池分配器(见下文)有用时,您永远不能将其视为引用类型。

自定义内存分配器

使用指针,您还可以创建自己的池分配器(这是非常简化的,删除了大量检查以显示原理):

type TreeNode {
  value int
  left  *TreeNode
  right *TreeNode

  nextFreeNode *TreeNode; // For memory allocation
}

var pool [1024]TreeNode
var firstFreeNode *TreeNode = &pool[0] 

func poolAlloc() *TreeNode {
    node := firstFreeNode
    firstFreeNode  = firstFreeNode.nextFreeNode
    return node
}

func freeNode(node *TreeNode) {
    node.nextFreeNode = firstFreeNode
    firstFreeNode = node
}

交换两个值

指针还允许您实现swap. 即交换两个变量的值:

func swap(a *int, b *int) {
   temp := *a
   *a = *b
   *b = temp
}

结论

Java 从来没有能够在 Google 等地方完全取代 C 进行系统编程,部分原因是由于缺乏控制内存布局和使用的能力(缓存未命中会显着影响性能),因此无法将性能调整到相同的范围。Go 的目标是在许多领域取代 C,因此需要支持指针。

2021-11-25