我有两种变量。检查Go playground,我不明白为什么会这样。问题:我从Models
获得的内容应该是struct
,以便将其用于GORM 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
}
答案 0 :(得分:1)
根据golang docs的大小和对齐保证
如果结构或数组类型不包含任何字段(或 元素,分别),大小大于零。二 不同的零大小变量在内存中可能具有相同的地址。
这就是Test 1
为&{}
接口值表示为给出指针的双字对 有关存储在接口中的类型和指向的信息 相关数据。
Test2
是interface{}
,因此Test2具有指向存储类型和指向数据本身的指针的信息的指针。它的类型和价值信息
答案 1 :(得分:1)
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
的包文档的格式规则:
对于复合对象,使用这些规则以递归方式打印元素,如下所示:
struct: {field0 field1 ...} array, slice: [elem0 elem1 ...] maps: map[key1:value1 key2:value2] pointer to above: &{}, &[], &map[]
由于它是指向struct
的指针,因此将使用&{}
格式。 Test
有一个字段Test string
,但您没有设置其值,因此默认为string
类型的zero value,这是空字符串{{ 1}}。这就是为什么你在展示时什么都看不见的原因。请注意,如果您将其初始化为:
""
输出应该是:
test1 := Test{"a"}
让我们看看你的第二个例子:
&{a}
第一行是short variable declaration,test2 := Models["test"]
// ...
fmt.Printf("%v", &test2)
的类型将从右侧表达式推断出来。右侧表达式是index expression,用于索引地图。它的类型将是地图的值类型,由于test2
的类型为Models
,map[string]interface{}
的类型将为test2
。
到目前为止一切顺利。但是当你尝试像interface{}
那样打印时会发生什么?您将指针传递给类型为fmt.Printf("%v", &test2)
的{{1}},因此您传递的是test2
类型,因为这与interface{}
不同,它将被包装另一个*interface{}
值。
因此传递给interface{}
的是interface{}
值,其中fmt.Printf()
值为interface{}
变量的地址。
现在适用于此处的格式规则:
%v的默认格式为:
*interface{}
由于要格式化的值是指针(test2
),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
获取结构,您可以使用type assertion。所以它应该是这样的:
0x1040a160
此test2
与t2 := Models["test"]
test2 := t2.(Test) // test2 is of type Test
具有相同的类型,并且在打印时会产生相同的结果。在Go Playground上尝试。
最好是在地图中存储test2
值,因此不需要类型断言甚至存储在局部变量中,因为存储在地图中的test1
已经是指针至*Test
,可按原样使用/传递。