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,这是空字符串""
。这就是为什么你显示时什么也看不到。请注意,如果你会喜欢这个初始化它:
test1 := Test{"a"}
输出本来:
&{a}
让我们看看你的第二个例子:
test2 := Models["test"]
// ...
fmt.Printf("%v", &test2)
第一行是short variable declaration ,test2
的类型将从右边的表达式中推断出来。右侧表达式是index expression,为地图编制索引。其类型将是地图的值类型,并且由于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
,即:
Pointe R:
%p base 16 notation, with leading 0x
所以结果是正确打印十六进制格式的地址值,例如:
0x1040a160
从test2
获得一个结构,你可以使用type assertion。所以它应该是这样的:
t2 := Models["test"]
test2 := t2.(Test) // test2 is of type Test
这test2
具有相同类型到的test1
,并在打印时会产生相同的结果。试试Go Playground。
最佳将是虽然存储*Test
值在地图,所以没有类型断言或偶存储在局部变量将是必要的,因为存储在地图的interface{}
将已经是指向Test
,其可用于/按照原样传递。
你应该在这里粘贴代码。简而言之,'test1'具有'Test'类型,'test2'具有'interface {}'类型(a.k.a空接口)。这是一种不同的类型。 – ymonad
@ymonad是的,我检查了它,但我怎样才能将它返回到正确的结构? – PumpkinSeed
当然,您可以将'map [string] interface {}'更改为'map [string] Test'。不过,我想这是[XY问题](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)。你有没有想要解决的具体问题? – ymonad