pointers - golang指针之间的区别

标签 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
}

最佳答案

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)

test1Test 类型,你传递的 &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

test2test1 的类型相同,打印时将产生相同的结果。在 Go Playground 上试用.

最好是将 *Test 值存储在映射中,因此不需要类型断言,甚至不需要存储在局部变量中,因为 interface{}存储在 map 中的已经是指向 Test 的指针,可以按原样使用/传递。

关于pointers - golang指针之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42039827/

相关文章:

c++ - 如何在 C++ 中将字符串变量的值赋给结构的字符串变量?

c++ - c++中struct的恼人问题

c - 在 C 中使用指针访问多维数组

c++ - 获取指针值

go - 如何解释 go pprof/mutex 显示等待解锁?

Golang switch 语句只调用函数一次

amazon-web-services - REST API 无法使用 https/ssl 进行重定向

c++ - 交叉编译器库交互(动态加载)(插件)

c - 指向结构体的指针中的元素数量

c++ - 释放空指针