我有两种变量。检查 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
}
最佳答案
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
包文档中的格式规则:
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[]
由于它是指向 struct
的指针,因此将使用 &{}
格式。 Test
有一个字段Test string
,但您没有设置它的值,所以它默认为 zero value string
类型的空字符串 ""
。这就是为什么在显示时您什么也看不到的原因。请注意,如果您像这样初始化它:
test1 := Test{"a"}
输出应该是:
&{a}
让我们看看你的第二个例子:
test2 := Models["test"]
// ...
fmt.Printf("%v", &test2)
第一行是short variable declaration , test2
的类型将从右侧表达式中推断出来。右边的表达式是 index expression , 索引 map 。它的类型将是 map 的值类型,并且由于 Models
的类型是 map[string]interface{}
,test2
的类型将是成为接口(interface){}
。
到目前为止一切顺利。但是,当您尝试像 fmt.Printf("%v", &test2)
那样打印时会发生什么?您传递了一个指向 test2
的指针,它是 interface{}
类型,所以您传递的是 *interface{}
类型,因为这与 interface{}
不同,它将被包装在另一个 interface{}
值中。
所以传递给 fmt.Printf()
的是一个 interface{}
值,包装一个 *interface{}
值作为test2
变量的地址。
现在适用于此处的格式规则:
The default format for %v is:
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
,即:
Pointer:
%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{}
存储在 map 中的已经是指向 Test
的指针,可以按原样使用/传递。
关于pointers - golang指针之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42039827/