Pointers golang指针之间的差异
我有两种变量。检查一下,我不明白为什么会这样。问题:我从Pointers golang指针之间的差异,pointers,go,struct,interface,formatting,Pointers,Go,Struct,Interface,Formatting,我有两种变量。检查一下,我不明白为什么会这样。问题:我从模型中得到的应该是一个结构,用于GORMFirst()函数 守则: package main import ( "fmt" ) type Test struct { Test string } var Models = map[string]interface{}{ "test": newTest(), } func main() { test1 := Test{} fmt.Println("
模型
中得到的应该是一个结构
,用于GORMFirst()
函数
守则:
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 docs的尺寸和对齐保证 如果结构或数组类型不包含字段(或 元素),其大小大于零。两个 不同的零大小变量在内存中可能具有相同的地址 这就是为什么测试1是
&{}
接口值表示为给出指针的两个字对
有关存储在接口中的类型的信息和指向
关联的数据
Test2
是一个接口{}
,因此Test2具有指向存储类型信息的指针和指向数据本身的指针。It类型和价值信息TL;DR:在第一种情况下,您通过了打印类型*Test
的值,但在第二种情况下,您通过了类型*interface{}
的值!%v
动词表示使用默认格式设置格式,但默认格式取决于值的类型
您看到的区别只是包实现的默认格式规则 您正在使用: 它将格式字符串和其他参数作为类型
接口{}
。因此请注意,如果传递的值不是interface{}
类型,则该值将被包装为interface{}
类型的值
现在让我们看看您的示例:
test1 := Test{}
// ...
fmt.Printf("%v", &test1)
test1
类型为Test
,您通过了&test1
类型为*Test
。这将被包装在接口{}
中。fmt
的包单据格式规则:
对于复合对象,元素使用以下规则以递归方式打印,布局如下:
struct: {field0 field1 ...}
array, slice: [elem0 elem1 ...]
maps: map[key1:value1 key2:value2]
pointer to above: &{}, &[], &map[]
test1 := Test{"a"}
t2 := Models["test"]
test2 := t2.(Test) // test2 is of type Test
由于它是指向结构的指针
,因此将使用&{}
格式<代码>测试有一个字段<代码>测试字符串,但您没有设置它的值,因此它默认为类型<代码>字符串,即空字符串<代码>“。这就是为什么显示时什么也看不到。请注意,如果您将其初始化为如下所示:
struct: {field0 field1 ...}
array, slice: [elem0 elem1 ...]
maps: map[key1:value1 key2:value2]
pointer to above: &{}, &[], &map[]
test1 := Test{"a"}
t2 := Models["test"]
test2 := t2.(Test) // test2 is of type Test
结果应该是:
&{a}
让我们看一下您的第二个示例:
test2 := Models["test"]
// ...
fmt.Printf("%v", &test2)
第一行是一种类型的test2
,将从右侧表达式中推断出来。右侧表达式是一个索引映射的表达式。它的类型将是映射的值类型,并且由于模型的类型是映射[string]接口{}
,因此test2的类型将是接口{}
到目前为止还不错。但是当您尝试像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
由于要格式化的值是指针(*接口{}
),%v
将默认为%p
,即:
指针:
%p base 16 notation, with leading 0x
因此,结果是以十六进制格式正确打印地址值,例如:
0x1040a160
要从test2
获取结构,可以使用。所以应该是这样的:
struct: {field0 field1 ...}
array, slice: [elem0 elem1 ...]
maps: map[key1:value1 key2:value2]
pointer to above: &{}, &[], &map[]
test1 := Test{"a"}
t2 := Models["test"]
test2 := t2.(Test) // test2 is of type Test
此test2
的类型与test1
的类型相同,打印时将产生相同的结果。试穿一下
最好是将*Test
值存储在映射中,这样就不需要类型断言,甚至不需要存储在局部变量中,因为映射中存储的接口{}
已经是指向Test
的指针,可以按原样使用/传递。您应该将代码粘贴到这里。简而言之,test1
的类型为Test
,test2
的类型为接口{}
(也称为空接口)。它是另一种类型。@ymonad是的,我检查了它,但是我如何才能返回正确的结构?当然,您可以将map[string]interface{}
更改为map[string]Test
。然而,我认为这是事实。您有什么具体问题需要解决吗?@ymonad模型数组中充满了with结构,我一直希望返回正确结构的实例。例如,有300个struct,它们都表示数据库表,我总是想返回一个我想要使用的表的实例。回答很好,大部分时间我都发现了这个问题,但目前我没有解决我的问题的方法:我在上面写了我的问题,你的建议是什么?“模型数组中充满了with结构,我一直想返回正确结构的实例。例如,有300个结构都表示数据库表,我总是想返回我想使用的表的实例”@Pumpkinsed我不理解你的示例,也许你应该把它作为一个新问题发布?我接受了它,我希望一切都可以理解: