当命名类型 T 的任何方法具有指针接收器时,复制类型 T 的实例

2023-12-10

I read Go 编程语言书籍最近学习golang编程语言的好资源。 6.2节中有一段关于类型的复制实例T当它是指针接收器或不在方法中时,我无法理解它。 有没有用一个有意义的例子来解释这一段?

6.2 使用指针接收器的方法

如果命名类型 T 的所有方法都有 T 本身的接收者类型(不是 *T ),则复制该类型的实例是安全的;调用它的任何方法都必然会生成一个副本。例如,time.Duration 值可以自由复制,包括作为函数的参数。但是,如果任何方法具有指针接收器,则应避免复制 T 的实例,因为这样做可能会违反内部不变量。例如,复制 bytes.Buffer 的实例将导致原始和副本别名(§2.3.2)相同的底层字节数组。后续的方法调用将产生不可预测的效果。

(Go 编程语言 Alan A. A. Donovan · Brian W. Kernighan)


调用方法时,首先复制调用该方法的值,然后将该副本传递/用作接收者。

如果一个类型只有带有值接收器的方法,这意味着无论这些方法在内部做什么,也无论您(或任何其他人)调用什么方法,这些方法都无法更改original值,因为如上所述,仅传递副本,并且该方法只能修改副本,而不能修改原始副本。

因此,这意味着如果您复制该值,则不必担心,在原始值或副本上调用的方法都不能/不会修改该值。

当类型具有带有指针接收器的方法时则不然。如果一个方法有一个指针接收者,该方法可以改变/修改pointed值,它不是副本,它是原始值(仅pointer是一个副本,但它指向原始值)。

让我们看一个例子。我们创建一个int包装类型,有 2 个字段:int and an *int。我们打算在两个字段中存储相同的数字,但其中一个是指针(并且我们存储int in the pointed value):

type Wrapper struct {
    v int
    p *int
}

为了确保两个值(v and *p)是一样的,我们提供一个Set()方法,同时设置:

func (w *Wrapper) Set(v int) {
    w.v = v
    *w.p = v
}

Wrapper.Set()有一个指针接收器(*Wrapper)因为它必须修改值(其类型为Wrapper)。无论我们转给什么号码Set(),我们可以确定一旦Set()返回,两者v and *p将是相同的,并且等于传递给的数字Set().

现在如果我们的值为Wrapper:

a := Wrapper{v: 0, p: new(int)}

我们可以调用Set()其方法:

a.Set(1)

编译器会自动获取地址a用作接收器,所以上面的代码意味着(&a).Set(1).

我们期望任何类型的值Wrapper具有相同的号码存储在Wrapper.v and *Wrapper.pv,如果只有Set()方法用于更改字段的值。

现在让我们看看如果我们复制以下问题a:

a := Wrapper{v: 0, p: new(int)}
b := a
fmt.Printf("a.v=%d, a.p=%d;  b.v=%d, b.p=%d\n", a.v, *a.p, b.v, *b.p)

a.Set(1)
fmt.Printf("a.v=%d, a.p=%d;  b.v=%d, b.p=%d\n", a.v, *a.p, b.v, *b.p)

输出(尝试一下去游乐场):

a.v=0, a.p=0;  b.v=0, b.p=0
a.v=1, a.p=1;  b.v=0, b.p=1

我们复制了一份a(将其存储在b),并打印这些值。到目前为止,一切都很好。然后我们打电话a.Set(1), 之后a还是不错的,但是内部状态b变得无效:b.v不等于*b.p不再了。解释很清楚:当我们复制a(这是一个struct类型),复制其字段的值(包括指针p),以及指针b将指向与指针相同的值a。因此修改指向的值将影响两个副本Wrapper,但我们有两个不同的v字段(它们是非指针)。

如果您有带有指针接收器的方法,则应该使用指针值。

请注意,如果您要复制值*Wrapper,一切都会很酷:

a := &Wrapper{v: 0, p: new(int)}
b := a
fmt.Printf("a.v=%d, a.p=%d;  b.v=%d, b.p=%d\n", a.v, *a.p, b.v, *b.p)

a.Set(1)
fmt.Printf("a.v=%d, a.p=%d;  b.v=%d, b.p=%d\n", a.v, *a.p, b.v, *b.p)

输出(尝试一下去游乐场):

a.v=0, a.p=0;  b.v=0, b.p=0
a.v=1, a.p=1;  b.v=1, b.p=1

在这种情况下a是一个指针,它的类型*Wrapper。我们制作了它的副本(将其存储在b),称为a.Set(),以及内部状态a and b仍然有效。这里我们只有一个Wrapper value, a只保存一个指向它的指针(它的地址)。当我们复制时a,我们只复制指针值,而不复制struct值(类型Wrapper).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当命名类型 T 的任何方法具有指针接收器时,复制类型 T 的实例 的相关文章

随机推荐

  • 无效的应用程序二进制文件[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 今天我们收到了有关我们提交的反馈 我们不明白所报告的问
  • 在node.js中读写json文件

    好的 我有这个 json 文件 joe name joe lastName black matt name matt lastName damon 我想用node js添加一个人 joe name joe lastName black ma
  • 以 S+(版本 31 及更高版本)为目标需要 FLAG_IMMUTABLE 或 FLAG_MUTABLE 之一

    我正在制作通知应用程序并努力解决以下错误 java lang IllegalArgumentException com tonyapp rabbitfarm Targeting S version 31 and above requires
  • Backbone.js - 从 url 返回 JSON

    在尝试学习 Backbone js 时 我一直在尝试使用以下代码获取 JSON 文件的内容 function var MyModel Backbone Model extend var MyCollection Backbone Colle
  • 在 R 中定义 CTE(公用表表达式)?

    我在服务器上有这个表 我正在使用 R 查询它 library dplyr library DBI con lt dbConnect RSQLite SQLite memory dbWriteTable con iris iris 我能够运行
  • 重新分配选票,同时淘汰候选人

    考虑一下这个想法 我有一个排名选择投票系统 不符合门槛的候选人将在不同轮次中被淘汰 在此示例中 我们有 6 名候选人在初选中竞选两个席位 此时 我们已进入第四轮 没有获胜者 其中候选人 3 和 5 已被淘汰 在这一轮中 候选人4将被淘汰 他
  • 克隆芹菜链

    我有一个有趣的问题 试图克隆芹菜链以在组中使用 我的预期用例是这样的group chain clone args args for args in it 然而它一直抱怨没有足够的论据 我已经使用下面的内容对此进行了分解 在一个名为tasks
  • 春季启动 JSP 404

    我正在尝试在我的 Spring Boot 服务中添加一个 jsp 页面 我的问题是 每次我尝试进入该页面时 我都会遇到以下问题 白标错误页面 此应用程序没有 error 的显式映射 因此您会看到 这是后备措施 2015 年 EEST 4 月
  • 如何为 MVC 创建自定义验证属性

    我想为 MVC2 的电子邮件地址创建一个自定义验证属性 该属性不是从 RegularExpressionAttribute 继承 但可以在客户端验证中使用 有人能指出我正确的方向吗 我尝试了这样简单的事情 AttributeUsage At
  • 如果 HTML 文件已更新,则执行 JavaScript [关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 我正在尝试在 JavaScript jQuery 甚至 PHP 中找到一个插件或函数 如
  • 从 URL 中删除应用程序名称

    我的网站使用 JSF 并且 url 似乎是 http mysitename com wompower6 faces home xhtml 我正在使用 Prettyfaces 因此如果我在 Pretty config xml 中使用以下内容
  • 如何在 PostgreSQL 中搜索一定范围的整数?

    我有一个整数列 我需要搜索该列以 19 开头的行 在 MySQL 中我会使用 SELECT WHEREid喜欢 19 ERROR operator does not exist integer unknown LINE 1 select f
  • 如何从 NSDictionary 获取键/值对?

    我在 NSDictionary 方面需要很少的帮助 如果我有字典 我怎样才能得到一对 让我们说一个 id 的值 NSDictionary allCourses NSJSONSerialization JSONObjectWithData a
  • Django 管理员。显示分层下拉过滤器

    我有以下模型 from django db import models class State models Model name models CharField max length 30 abbreviation models Cha
  • Azure-Functions:您可以使用 web.config 限制(例如 IP 限制或基本身份验证)

    Azure 网站可能存在 IP 限制 as 正在使用基本身份验证保护站点 这些技术或任何其他 web config 技术是否可以在 Azure Functions 上使用 或者是否需要进行编码 我在 Azure Function 的 www
  • AchartEngine 中的圆环图半径

    我正在尝试在 aChartengine 中设置圆环图内圆半径和外圆半径 下面是我的代码 public class MainActivity extends Activity GraphicalView gv RelativeLayout r
  • 如何在 Bottle 中将 wsgi.url_scheme 设置为 https?

    我想将所有请求重定向到http to https 是否有通用的设置方法wsgi url scheme to https在 Python 2 7 Bottle 应用程序中 应用程序的一般结构是 setup py contains instal
  • Maven 中的传递 AAR 依赖项

    我正在从使用 android maven plugin 的 Maven 项目构建 Android 应用程序 在这个项目中 我使用新的测试版数据绑定库 它包含在 Android SDK 的本地 m2repository extras andr
  • 使用 CSS GRID 为什么我会出现这种差距?

    我正在学习 CSS GRID 但我不知道为什么在下面的示例中出现空白 第二个项目可以适合第一个轨道 但我却在那里出现了间隙 这是代码 container display grid margin 40px grid gap 20px text
  • 当命名类型 T 的任何方法具有指针接收器时,复制类型 T 的实例

    I read Go 编程语言书籍最近学习golang编程语言的好资源 6 2节中有一段关于类型的复制实例T当它是指针接收器或不在方法中时 我无法理解它 有没有用一个有意义的例子来解释这一段 6 2 使用指针接收器的方法 如果命名类型 T 的