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("

我有两种变量。检查一下,我不明白为什么会这样。问题:我从
模型
中得到的应该是一个
结构
,用于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
}

根据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我不理解你的示例,也许你应该把它作为一个新问题发布?我接受了它,我希望一切都可以理解: