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

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

问题描述

我有两种变量。检查去操场,我不明白为什么会发生这种情况。问题:我从 Models 得到的结果应该是 struct 用于GORM First() function。



代码:

 < 













}

模型= map [string]接口{} {
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


解决方案迪在第一种情况下,你传递一个 * Test 类型的值来打印,但是在第二种情况下,传递 * interface {} 类型的值! %v 动词表示使用默认格式设置格式,但默认格式取决于值的类型。



< hr>

您看到的差异只是的默认格式化规则 fmt 包的实现。



您正在使用 fmt.Printf()

  func Printf(格式字符串,a ...接口{})(n int,err错误)

将格式字符串和其他参数作为类型 interface {} 。所以请注意,如果您传递的值不是 interface {} 类型,则该值将被封装在类型为 interface {}的值中code $。

现在我们来看看你的例子:

$ p $ test1:= Test {}
// ...
fmt.Printf(%v,& test1)

test1 类型为 Test ,并且传入& test1 ,它的类型是 * Test 。这将被包装在界面{} 中。从 fmt


的包文档中的格式规则对于复合对象,元素使用这些规则打印,递归,如下所示:

  struct:{field0 field1 ...} 
array,slice:[elem0 elem1 ...]
maps:map [key1:value1 key2:value2]
指向上面的指针:& {},& [],& map []


由于它是一个指向 struct ,将使用& {} 格式。 Test 有一个字段测试字符串,但是您没有设置它的值,所以它默认为 rel =nofollow noreferrer>零值类型 string 这是空的字符串。这就是为什么你显示时什么也看不到请注意,如果你想这样初始化它:

  test1:= Test {a} 

code>

输出结果如下:

 <$ c 




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

  test2:= Models [test] 
// ...
fmt.Printf(%v,& test2)

第一行是短变量声明 test2 类型将从右侧表达式推断出来。右侧的表达式是一个索引表达式,为地图编制索引。它的类型将是map的值类型,因为 Models 的类型是 map [string] interface {} test2 类型将会是 interface {}



迄今为止很好。但是当你试图像 fmt.Printf(%v,& test2)打印时会发生什么呢?你传递一个指向 test2 的类型为 interface {} 的指针,所以你传入的类型是 * interface {} ,因为它与 interface {} 不一样,所以它会被包装在另一个 interface {} value。



所以传递给 fmt.Printf()是一个接口{} 值,它包含一个 * interface {} 值,它是 test2 变量。



现在适用的格式规则:

lockquote >

%v的默认格式为:

  bool:%t 
int, int8等:%d
uint,uint8等:%d,%x如果用%#v
float32,complex64等打印:%g
字符串:%s
chan:%p
指针:%p


由于要格式化的值是一个指针( * interface {} ), %v 会默认为%p ,即:

< blockquote>

指针:

 %p基数16表示法,带有前导0x 





$ b

所以结果是正确的打印十六进制格式的地址值,例如:

  0x1040a160 






要从 test2 获取一个结构,可以使用键入断言。所以它应该是这样的:

  t2:= Models [test] 
test2:= t2 。(Test)// test2的类型是Test

这个 test2 具有与 test1 相同的类型,并且在打印时将产生相同的结果。试试去游乐场



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


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.

The code:

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: 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.


The difference you see is just the default formatting rules of the fmt package's implementation.

You're using fmt.Printf():

func Printf(format string, a ...interface{}) (n int, err error)

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 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[]

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

The output would have been:

&{a}

Let's see your 2nd example:

test2 := Models["test"]
// ...
fmt.Printf("%v", &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{}.

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.

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:

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

Since the value to be formatted is a pointer (*interface{}), %v will default to %p, which is:

Pointer:

%p    base 16 notation, with leading 0x

So the result is properly printing the address value in hexadecimal format, e.g.:

0x1040a160


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

This test2 has identical type to that of test1, and will produce the same result when printing. Try it on the Go Playground.

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天全站免登陆