Go语言中指向结构或数组值的指针如何工作? [英] How does a pointer to a struct or array value in Go work?

查看:130
本文介绍了Go语言中指向结构或数组值的指针如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下Go结构:

type Person struct {
    Name    string
    Age     int
    Country string
}

我多次遇到以下用途:

p := &Person{"Adam", 33, "Argentina"}

但是我看不到指向struct值的意义,我想知道它与以下内容有何不同:

n := &999 // Error

我的问题是:

  1. 即使它是结构或数组而不是诸如字符串或int之类的原语,如何甚至指向一个值呢?奇怪的是,以下内容对我的理解没有帮助:

    fmt.Println(p, &p) // outputs: &{Adam 33 Argentina} 0xc042084018
    

  2. 程序员为什么要通过指针声明结构实例?这样做能达到什么目的?

解决方案

&Person{}是一种语言"construct",属于规范:它分配了一个Person类型的新变量,并为您提供地址该匿名变量.

规范:复合文字:

获取复合文字的地址会生成指向唯一变量.

也:规范:变量:

调用内置函数获取<一个href ="https://golang.org/ref/spec#Composite_literals" rel ="nofollow noreferrer">复合文字在运行时为变量分配存储空间..

语言规范不允许使用

&999.地址运算符的可能操作数列在规范:地址运算符:

操作数必须是可可寻址的,即变量,指针间接访问或切片索引操作;或可寻址结构操作数的字段选择器;或可寻址数组的数组索引操作.作为可寻址性要求的例外,x也可以是复合文字.

p := Person{}创建一个新的变量p,其类型将为Person. p := &Person{}创建一个新的变量,其类型将为*Person.

查看可能的重复项:我该如何在Go中使用文字* int64吗?

使用 fmt 包打印值时,它具有某些规则,该规则如何打印不同类型的值:

对于复合对象,将使用以下规则递归地打印元素,如下所示:

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

当您使用fmt.Println()时,将应用默认的格式设置规则,对于*int类型的值,它是%p动词,它将以十六进制格式打印内存地址,但用于指向struct的指针它打印以&符号(&{})开头的结构值.您可以在以下相关问题中了解更多信息: golang指针之间的差异

如果要打印指针值,请取消引用指针并传递指针值,例如:

var p = new(int)
*p = 12
fmt.Println(*p) // Prints 12

关于为什么要创建一个指向值(而不是值)的指针,请参见以下相关问题:

参数与返回值中指针与值的比较

为什么Go的构造函数应返回地址?

Go,X不会实现Y (...方法有一个指针接收器)

Considering the following Go struct:

type Person struct {
    Name    string
    Age     int
    Country string
}

I have encountered numerious times the following use:

p := &Person{"Adam", 33, "Argentina"}

Yet I can not see the point in pointing to a struct value, and I wonder, how does it differ from:

n := &999 // Error

My questions are:

  1. How is it even possible to point to a value, even if it is a struct or array and not a primitive like a string or int? Strange enough, the following doesn't contribute to my understanding:

    fmt.Println(p, &p) // outputs: &{Adam 33 Argentina} 0xc042084018
    

  2. Why would a programmer want to declare a struct instance by a pointer? What could you achieve doing so?

解决方案

&Person{} is a language "construct", it's part of the spec: it allocates a new variable of Person type, and provides you the address of that anonymous variable.

Spec: Composite literals:

Taking the address of a composite literal generates a pointer to a unique variable initialized with the literal's value.

Also: Spec: Variables:

Calling the built-in function new or taking the address of a composite literal allocates storage for a variable at run time.

&999 is not allowed by the language spec. The possible operands of the address operators are listed in the Spec: Address operators:

The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.

p := Person{} creates a new variable p whose type will be Person. p := &Person{} creates a new variable whose type will be *Person.

See possible duplicate: How do I do a literal *int64 in Go?

When you print the values with the fmt package, it has certain rules how to print values of different types:

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[]

When you use fmt.Println(), the default formatting rules will be applied, which for a value of type *int is the %p verb, which will print the memory address in hexadecimal format, but for a pointer to struct it prints the struct value prepended with an & sign (&{}). You can read more about it in related question: Difference between golang pointers

If you want to print the pointed value, dereference the pointer and pass the pointed value, e.g.:

var p = new(int)
*p = 12
fmt.Println(*p) // Prints 12

As to why to create a pointer to a value (and not a value), see these related questions:

Pointers vs. values in parameters and return values

Why should constructor of Go return address?

Go, X does not implement Y (... method has a pointer receiver)

这篇关于Go语言中指向结构或数组值的指针如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆