【问题标题】:Is there a general name for Go types with "reference semantics" such as map, slice and channel?是否有具有“参考语义”的 Go 类型的通用名称,例如 map、slice 和 channel?
【发布时间】:2021-01-14 10:27:16
【问题描述】:

根据Go: reference types as arguments 中的响应和 cmets,Go 似乎没有“官方”称为“引用类型”的类型。

然而,有些类型实际上持有指向底层数据的指针,这允许有效地将这些类型的值作为函数参数传递,而无需获取指向它们的指针。当这样的值作为函数参数传递时,没有(或像切片一样很少)复制底层数据,因此如果程序员获取指向类型的指针并传递它,则没有(或很少)效率增益指针作为函数参数而不是值。

根据the accepted answer,这些类型是slicesma​​pschannels

Effective Go 官方文档describes Slices 为:

切片包含对底层数组的引用,如果将一个切片分配给另一个切片,则两者都引用同一个数组。如果一个函数接受一个切片参数,它对切片元素所做的更改将对调用者可见,类似于传递一个指向底层数组的指针。

Maps 为:

与切片一样,映射包含对底层数据结构的引用。如果您将地图传递给更改地图内容的函数,则更改将在调用者中可见。

Channels 为:

像地图一样,通道是用 make 分配的,结果值充当对底层数据结构的引用。

无论出于何种原因,文档似乎都避免对这些类型使用“引用类型”一词,但在每种情况下仍然提到“引用”一词。

这些类型的特别之处还在于可以将nil 分配给这种类型的值,类似于指针类型(doc):

如果满足以下条件之一,则值 x 可分配给 T 类型的变量(“x 可分配给 T”):
...

  • x 是预声明的标识符 nilT 是指针、函数、切片、映射、通道或接口类型。

在日常程序员的实践中,很重要了解、清楚地区分和清楚地传达作为函数参数传递时共享底层数据与不共享底层数据的类型或数据结构(但复制)基础数据。

在与其他程序员,尤其是初级程序员交谈时,能够将 slicesma​​pschannels 作为一个单独的组来引用是一种清晰的通信有助于确保程序中的数据安全并识别/预防与改变共享状态相关的危险。

这组类型一般怎么称呼?

【问题讨论】:

标签: go


【解决方案1】:

一般如何调用这组[切片、映射、函数和方法以及通道]类型?

这个问题是错误的,因为方法不是 Go 中的类型,而函数类型只是函数,不适合关于“引用”的讨论。 假设你想讨论切片、映射、闭包和缓冲通道:

这些被称为“切片、映射、闭包和缓冲通道”,可能不需要为这 4 个命名:它们没有太多共同点。

以下四种类型展示了引用语义:切片、映射、闭包和缓冲通道。 (无缓冲通道没有)。

  • 切片是一种值类型,可将视图呈现到支持数组中。因此,它具有关于存储在支持数组中的值的引用语义。
  • 映射是一个映射,具有关于映射中存储的值的引用语义。 (这个最接近引用类型。)
  • 函数关闭器是闭包并且很复杂,根据价值所有权与初级人员讨论它们可能没有帮助)。
  • 缓冲通道显示关于缓冲值的引用语义。

不需要一个复杂的术语(除非你从事学术工作,分类、分离和分类是你的生活。)

【讨论】:

  • 这个答案基本上是正确的,尽管“类型表现出引用语义”可能对不同的人意味着不同的东西。如果将 Go 与区分引用类型和值类型的 C# 之类的语言进行比较,则肯定存在从语法中看不到的区别。在 Go 或 C 或 C# 中,参数总是按值传递,但是在函数内部向 map 添加值会改变原始对象(即使映射是按值传递的),同时调用内部自定义结构的方法该方法可能会改变结构,但不会影响外部世界。
  • 1) 没有复杂术语的请求。从答案中脱颖而出,您提出的定义是“具有引用语义的类型”。它是否正确? 2) 基于不适合该组的功能/方法将问题标记为“荒谬”是没有价值的。这是从链接的答案中获取的。请在那里发表评论并帮助改进它。我从问题中删除了提及。 3)答案给人的印象是这个问题毫无价值;令人惊讶的是它仍然得到了回答。也许,如果你去掉情感背景,答案会更有价值?
  • @Mike 1) 不。“具有引用语义的类型”的问题是,如果许多结构类型包含导致 3) 的指针字段,它们也会显示引用语义 3) 是的,我认为不是有利于在这里发明一个术语或分类法。 Go 中的类型数量非常少,它们根本不属于很多自然类,你必须学习规则。您必须了解指针类型是什么以及适用哪些规则(例如,您不能在指针类型上定义方法)。同样,您只需了解切片是什么:
  • @Mike 切片是一个支持数组的视图。缓冲通道也是如此。或者函数闭包。您必须了解 闭包 并且函数是 Go 中的第一类类型。复制函数闭包或缓冲通道不会复制关闭或缓冲的内容这一事实非常自然,并且不需要虚构的术语即可理解。对于2)我稍微改变了答案。
  • 重要的是,如果您将通道值传递给函数,该函数将具有相同的通道,而不是副本。它仍然是引用语义;它是否“存储”值并不重要。如果它不是引用语义,则必须传递指向通道的指针才能按预期工作。
猜你喜欢
  • 2011-01-07
  • 1970-01-01
  • 1970-01-01
  • 2018-11-03
  • 2013-01-18
  • 1970-01-01
  • 2012-05-01
  • 2016-01-12
相关资源
最近更新 更多