golang指针之间的区别

时间:2017-02-04 11:29:18

标签: pointers go struct interface formatting

我有两种变量。检查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
}

2 个答案:

答案 0 :(得分:1)

根据golang docs的大小和对齐保证

  

如果结构或数组类型不包含任何字段(或   元素,分别),大小大于零。二   不同的零大小变量在内存中可能具有相同的地址。

这就是Test 1&{}

的原因
  

接口值表示为给出指针的双字对   有关存储在接口中的类型和指向的信息   相关数据。

Test2interface{},因此Test2具有指向存储类型和指向数据本身的指针的信息的指针。它的类型和价值信息

答案 1 :(得分:1)

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,这是空字符串{{ 1}}。这就是为什么你在展示时什么都看不见的原因。请注意,如果您将其初始化为:

""

输出应该是:

test1 := Test{"a"}

让我们看看你的第二个例子:

&{a}

第一行是short variable declarationtest2 := Models["test"] // ... fmt.Printf("%v", &test2) 的类型将从右侧表达式推断出来。右侧表达式是index expression,用于索引地图。它的类型将是地图的值类型,由于test2的类型为Modelsmap[string]interface{}的类型将为test2

到目前为止一切顺利。但是当你尝试像interface{}那样打印时会发生什么?您将指针传递给类型为fmt.Printf("%v", &test2)的{​​{1}},因此您传递的是test2类型,因为这与interface{}不同,它将被包装另一个*interface{}值。

因此传递给interface{}的是interface{}值,其中fmt.Printf()值为interface{}变量的地址。

现在适用于此处的格式规则:

  

%v的默认格式为:

*interface{}

由于要格式化的值是指针(test2),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 base 16 notation, with leading 0x 获取结构,您可以使用type assertion。所以它应该是这样的:

0x1040a160

test2t2 := Models["test"] test2 := t2.(Test) // test2 is of type Test 具有相同的类型,并且在打印时会产生相同的结果。在Go Playground上尝试。

最好是在地图中存储test2值,因此不需要类型断言甚至存储在局部变量中,因为存储在地图中的test1已经是指针至*Test,可按原样使用/传递。