gpt4 book ai didi

Go struct 方法允许类型混合?

转载 作者:IT王子 更新时间:2023-10-29 02:26:15 26 4
gpt4 key购买 nike

我有一个只有一个方法的简单结构:

type Person struct {
name string
}

func (p Person) SetName(name string) {
p.name = name
}

以下输出:

dave := Person{}
dave.SetName("Dave")
fmt.Println(dave.name)

将是空的,因为方法接收器接受一个值(或更准确地创建您传递的值的副本),因此它不会修改您的基础值。

如果我将方法更改为:

func (p *Person) SetName(name string) {
p.name = name
}

输出将是“Dave”。

现在我不明白的是我不应该在指针上调用方法吗?所以在初始化我的对象时我应该这样做:

dave := &Person{}

而不是这个:

dave := Person{}

我还尝试使用 go 的 reflect 包来找出以下值:

&Person

并发现它是 *Person,这很好。与打印指向 int 的指针的值相比,当我打印值时虽然没有获得内存位置:

a := 4
fmt.Println(&a)

我一直在阅读文档,就此提出问题,但我了解得越多,我就越想知道我是否遗漏了一些简单的东西,因为很多人认为这一切并不令人困惑。

最佳答案

您混淆了在指针接收器上调用方法与保持指向值的指针。也就是说,在指针接收器上定义的调用 SetName 与存储指针到内存中的指针之间没有内在连接,该内存包含 Person< 类型的值 与直接存储 Person

当你有声明时

var pers Person

然后调用

pers.SetName("foo")

编译器取其占用的内存块地址变量 pers — 就像您通过应用程序手动执行此操作一样& 运算符到 pers,并将该地址传递给 SetName函数,所以调用最终会像

(&pers).SetName("foo")

或者,换句话说,SetName 的接收者将是&pers——即pers的地址。

现在没有什么能阻止你获取 pers 的地址并将其存储在别处:

var ptr *Person = &pers

(你通常不会写这样的 Java 风格的卡顿代码,但是我这样做是为了更加清晰),现在你可以打电话了SetName 就在 ptr 值上:

ptr.SetName("bar")

现在编译器将直接使用存储在变量ptr中的值将其作为方法的接收者传递。

这个“谜题”的最后一点是当你使用Go 提供的特殊语法——应用地址获取运算符 &直接转换为文字——编译器会做这样的事情:

var __pers Person = Person{
// The contents of your literal
}
var dave = &__pers

...并使 __pers 变量无法通过名称访问(因为它自然没有名字)。

如你所见,这与获取指针没有区别手动保存到 Person 值的内存中。


您可能想咨询this FAQ entry获得更多的了解该方法如何设置类型 T*T 相关,以及为什么后者总是包括前者但不包括前者。另请阅读 this .


更新: 解释 fmt.Println 格式和输出方式的差异*int*Person 类型的值。

  • 前者打印为 base-16 字符串表示包含该 int 值的内存位置的地址。
  • 后者是使用类似于Go 将指针指向文字的语法:&{}

此行为已记录在案:fmt.Printfmt.Println对它们的参数使用所谓的默认格式规则被传递,这些规则取决于参数的类型。

让我们首先查阅关于fmt.Println的文档(运行 go doc fmt.Println):

func Println(a ...interface{}) (n int, err error)

Println formats using the default formats for its operands and writes to standard output. Spaces are always added between operands and a newline is appended. It returns the number of bytes written and any write error encountered.

(强调我的。)

现在让我们转向fmt包本身的文档(运行 go doc fmt):

<…>

Printing

The verbs:

General:

  • %v the value in a default format

    when printing structs, the plus flag (%+v) adds field names.

<…>

The default format for %v is:

bool:                    %t
int, int8 etc.: %d
uint, uint8 etc.: %d, %#x if printed with %#v
float32, complex64, etc: %g
string: %s
chan: %p
pointer: %p

For compound objects, the elements are printed using these rules, recursively, laid out like this:

struct:             {field0 field1 ...}
array, slice: [elem0 elem1 ...]
maps: map[key1:value1 key2:value2]
pointer to above: &{}, &[], &map[]

A *Person 是一个指向结构类型的指针,所以它呈现为

&{name}

其中name是name字段的内容;说,如果它被分配字符串“Dave”,输出将是 &{dave}

关于Go struct 方法允许类型混合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49251583/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com