![](/img/trans.png)
[英]Difference between Golang struct literals & pointers when accessing struct fields
[英]Difference between golang pointers
我有2种变量。 检查Go游乐场 ,我不明白为什么会这样。 问题:我从一开始Models
应该是一个struct
使用它的格姆First()
函数。
编码:
package main
import (
"fmt"
)
type Test struct {
Test string
}
var Models = map[string]interface{}{
"test": newTest(),
}
func main() {
test1 := Test{}
fmt.Println("Test 1: ")
fmt.Printf("%v", test1)
fmt.Println()
fmt.Println("Test 1 as pointer: ")
fmt.Printf("%v", &test1)
fmt.Println()
test2 := Models["test"]
fmt.Println("Test 2: ")
fmt.Printf("%v", test2)
fmt.Println()
fmt.Println("Test 2 as pointer: ")
fmt.Printf("%v", &test2)
}
func newTest() Test {
var model Test
return model
}
根据golang文档的大小和对齐方式保证
如果结构或数组类型不包含大小大于零的字段(或元素),则其大小为零。 两个不同的零大小变量在内存中可能具有相同的地址。
这就是为什么Test 1
是&{}
接口值表示为两个单词对,它提供了一个指针,该指针指向有关接口中存储的类型的信息,以及一个指向关联数据的指针。
Test2
是一个interface{}
,因此Test2具有指向有关存储的类型的信息的指针和指向数据本身的指针。 它的类型和值信息
TL; DR:在第一种情况下,您传递了*Test
类型用于打印,但是在第二种情况下,您传递了*interface{}
类型的值! %v
动词表示使用默认格式进行格式化,但是默认格式取决于值的类型。
您看到的区别只是fmt
包实现的默认格式设置规则。
您正在使用fmt.Printf()
:
func Printf(format string, a ...interface{}) (n int, err error)
它使用格式字符串和其他参数作为interface{}
类型。 因此请注意,如果您传递的值不是interface{}
类型,则该值将被包装在interface{}
类型的值中。
现在,让我们看一下您的示例:
test1 := Test{}
// ...
fmt.Printf("%v", &test1)
test1
的类型为Test
,并且您传递的&test1
的类型为*Test
。 这将包装在interface{}
。 来自fmt
软件包doc的格式化规则:
对于复合对象,使用以下规则递归地打印元素,其布局如下:
struct: {field0 field1 ...} array, slice: [elem0 elem1 ...] maps: map[key1:value1 key2:value2] pointer to above: &{}, &[], &map[]
由于它是指向struct
的指针,因此将使用&{}
格式。 Test
有一个字段Test string
,但是您没有设置它的值,因此它默认为类型string
的零值 ,即空字符串""
。 这就是为什么在显示时什么也看不到的原因。 请注意,如果要像这样初始化它:
test1 := Test{"a"}
输出为:
&{a}
让我们来看第二个例子:
test2 := Models["test"]
// ...
fmt.Printf("%v", &test2)
第一行是简短的变量声明 ,将从右侧表达式推断出test2
类型。 右边的表达式是一个索引表达式 ,索引一个地图。 它的类型将是映射的值类型,并且由于Models
类型是map[string]interface{}
,因此test2
类型将是interface{}
。
到现在为止还挺好。 但是,当您尝试像fmt.Printf("%v", &test2)
一样打印时会发生什么? 您传递了一个指向test2
的指针,该指针的类型为interface{}
,因此传递的类型为*interface{}
,并且由于它与interface{}
,因此它将被包装在另一个interface{}
值中。
因此,传递给fmt.Printf()
是interface{}
值,将*interface{}
值包装为test2
变量的地址。
现在适用于此处的格式设置规则:
%v的默认格式为:
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
由于要格式化的值是指针( *interface{}
),因此%v
将默认为%p
,即:
指针:
%p base 16 notation, with leading 0x
因此,结果是正确以十六进制格式打印地址值,例如:
0x1040a160
要从test2
获取结构,可以使用类型断言 。 因此它应该是这样的:
t2 := Models["test"]
test2 := t2.(Test) // test2 is of type Test
该test2
具有与test1
相同的类型,并且在打印时将产生相同的结果。 在Go Playground上尝试一下。
最好是将*Test
值存储在映射中,因此不需要类型声明,甚至不需要存储在局部变量中,因为存储在映射中的interface{}
已经是指向Test
的指针,可以使用/照原样通过。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.