golang指针的区别 [英] Difference between golang pointers

查看:18
本文介绍了golang指针的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两种变量.检查 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 包的实现.

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)

test1Test 类型,你通过 &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

test2test1的类型相同,打印时会产生相同的结果.在 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆