我有2种变量。检查Go游乐场,我不明白为什么会这样。问题:我从中得到的Models应该是struct将其用于GORM First()功能。
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 }
TL; DR: 在第一种情况下,您传递了*Test用于打印的type值,但在第二种情况下,您传递了type的值*interface{}!该%v动词表示使用默认格式进行格式化,但是默认格式取决于值的类型。
*Test
*interface{}
%v
您看到的区别只是fmt包实现的默认格式设置规则。
fmt
您正在使用fmt.Printf():
fmt.Printf()
func Printf(format string, a ...interface{}) (n int, err error)
它以格式字符串和其他参数作为类型interface{}。因此请注意,如果您传递的值不是type interface{},则该值将被包装为type值interface{}。
interface{}
现在,让我们看看您的示例:
test1 := Test{} // ... fmt.Printf("%v", &test1)
test1是类型的Test,而您通过的&test1是类型*Test。这将包装在interface{}。来自的打包文档的格式规则fmt:
test1
Test
&test1
对于复合对象,将使用以下规则递归地打印元素,其布局如下: struct: {field0 field1 ...} array, slice: [elem0 elem1 ...] maps: map[key1:value1 key2:value2] pointer to above: &{}, &[], &map[]
对于复合对象,将使用以下规则递归地打印元素,其布局如下:
struct: {field0 field1 ...} array, slice: [elem0 elem1 ...] maps: map[key1:value1 key2:value2] pointer to above: &{}, &[], &map[]
由于它是指向的指针struct,因此&{}将使用该格式。Test有一个字段Test string,但是您没有设置它的值,因此它默认为空字符串类型的零值。这就是为什么在显示时什么也看不到的原因。请注意,如果您要像这样初始化它:string``""
&{}
Test string
string``""
test1 := Test{"a"}
输出为:
&{a}
让我们来看第二个例子:
test2 := Models["test"] // ... fmt.Printf("%v", &test2)
第一行是一个简短的变量声明,类型test2将从右侧表达式中推断出来。右侧表达式是一个索引表达式,为地图建立索引。其类型将是映射的值类型,并且由于类型为Modelsis map[string]interface{},所以类型of test2将为interface{}。
test2
map[string]interface{}
到目前为止,一切都很好。但是,当您尝试像这样打印时会发生什么fmt.Printf("%v", &test2)?您传递的指针test2类型是interface{},所以传递的类型是*interface{},并且由于与并不相同interface{},它将被包装在另一个interface{}值中。
fmt.Printf("%v", &test2)
因此,传递给它的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
%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
指针: %p base 16 notation, with leading 0x
指针:
%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,可以按原样使用/传递它。