golang指针的区别 [英] Difference between golang pointers
问题描述
我有两种变量.检查 Go playground,我不明白为什么会这样.问题:我从 Models
得到的应该是一个 struct
用于 GORM First()
函数.
There are 2 kinds of variables that I have. Check for the Go playground, and I don't understand why this is happening. The problem: what I get from the Models
it should be a struct
to use it for GORM First()
function.
代码:
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
动词表示使用默认格式进行格式化,但默认格式取决于值的类型.
TL;DR: In the first case you pass a value of type *Test
for printing, but in the second case you pass a value of type *interface{}
! The %v
verb means to format using the default formatting, but the default formatting depends on the type of the value.
你看到的区别只是fmt
的默认格式规则a> 包的实现.
The difference you see is just the default formatting rules of the fmt
package's implementation.
您正在使用 fmt.Printf()
:
You're using fmt.Printf()
:
func Printf(format string, a ...interface{}) (n int, err error)
采用格式字符串和其他参数作为 interface{}
类型.因此请注意,如果您传递的值不是 interface{}
类型的值,则该值将包含在 interface{}
类型的值中.
which takes a format string and other arguments as type interface{}
. So note that if the value you pass is not of type interface{}
, the value will be wrapped in a value of type interface{}
.
现在让我们看看您的示例:
Now let's see your examples:
test1 := Test{}
// ...
fmt.Printf("%v", &test1)
test1
是 Test
类型,你通过 &test1
,它是 *Test
类型.这将封装在 interface{}
中.fmt
包文档中的格式规则:
test1
is of type Test
, and you pass &test1
which is of type *Test
. This will be wrapped in an interface{}
. The formatting rules from the package doc of 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
,但是你没有设置它的值,所以它默认为 零值 类型 string
是空字符串 ""
.这就是为什么在显示时您什么也看不到的原因.请注意,如果您像这样初始化它:
Since it is a pointer to a struct
, the &{}
format will be used. Test
has a field Test string
, but you didn't set its value, so it defaults to the zero value of the type string
which is the empty string ""
. That's why you see nothing when displayed. Note that if you would have initialized it like this:
test1 := Test{"a"}
输出应该是:
&{a}
让我们看看你的第二个例子:
Let's see your 2nd example:
test2 := Models["test"]
// ...
fmt.Printf("%v", &test2)
第一行是短变量声明,类型为test2
将从右侧的表达式中推断出来.右侧的表达式是一个 索引表达式,用于索引地图.它的类型将是地图的值类型,并且由于 Models
的类型是 map[string]interface{}
,test2
的类型将成为接口{}
.
The first line is a short variable declaration, type of test2
will be inferred from the right-hand side expression. The right hand side expression is an index expression, indexing a map. Its type will be the value type of the map, and since type of Models
is map[string]interface{}
, type of test2
will be interface{}
.
到目前为止一切顺利.但是当您尝试像 fmt.Printf("%v", &test2)
一样打印它时会发生什么?你传递一个指向 test2
的指针,它是 interface{}
类型,所以你传递的是 *interface{}
类型,并且由于这个与 interface{}
不同,它将被包装在另一个 interface{}
值中.
So far so good. But what happens when you try to print it like fmt.Printf("%v", &test2)
? You pass a pointer to test2
which is of type interface{}
, so what you pass is of type *interface{}
, and since this is not identical to interface{}
, it will be wrapped in another interface{}
value.
所以传递给 fmt.Printf()
的是一个 interface{}
值,包装一个 *interface{}
值是test2
变量的地址.
So what gets passed to fmt.Printf()
is an interface{}
value, wrapping a *interface{}
value being the address of the test2
variable.
现在适用于此处的格式规则:
And now the formatting rule that applies here:
%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
由于要格式化的值是一个指针(*interface{}
),%v
将默认为%p
,即:
Since the value to be formatted is a pointer (*interface{}
), %v
will default to %p
, which is:
指针:
%p base 16 notation, with leading 0x
所以结果是以十六进制格式正确打印地址值,例如:
So the result is properly printing the address value in hexadecimal format, e.g.:
0x1040a160
要从 test2
获取结构体,您可以使用 类型断言一>.所以它应该是这样的:
To obtain a struct from test2
, you can use type assertion. So it should rather be something like this:
t2 := Models["test"]
test2 := t2.(Test) // test2 is of type Test
此test2
与test1
的类型相同,打印时会产生相同的结果.在 Go Playground 上试试.
This test2
has identical type to that of test1
, and will produce the same result when printing. Try it on the Go Playground.
最好将 *Test
值存储在映射中,因此不需要类型断言,甚至不需要存储在局部变量中,因为 interface{}
存储在映射中的指针已经是指向 Test
的指针,它可以按原样使用/传递.
Best would be though to store *Test
values in the map, and so no type assertion or even storing in local variable would be necessary, as the interface{}
stored in the map would already be a pointer to Test
, which can be used / passed around as-is.
这篇关于golang指针的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!