繁体   English   中英

Golang指针之间的区别

[英]Difference between golang pointers

我有2种变量。 检查Go游乐场 ,我不明白为什么会这样。 问题:我从一开始Models应该是一个struct使用它的格姆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
}

根据golang文档的大小和对齐方式保证

如果结构或数组类型不包含大小大于零的字段(或元素),则其大小为零。 两个不同的零大小变量在内存中可能具有相同的地址。

这就是为什么Test 1&{}

接口值表示为两个单词对,它提供了一个指针,该指针指向有关接口中存储的类型的信息,以及一个指向关联数据的指针。

Test2是一个interface{} ,因此Test2具有指向有关存储的类型的信息的指针和指向数据本身的指针。 它的类型和值信息

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软件包doc的格式化规则:

对于复合对象,使用以下规则递归地打印元素,其布局如下:

 struct: {field0 field1 ...} array, slice: [elem0 elem1 ...] maps: map[key1:value1 key2:value2] pointer to above: &{}, &[], &map[] 

由于它是指向struct的指针,因此将使用&{}格式。 Test有一个字段Test string ,但是您没有设置它的值,因此它默认为类型string零值 ,即空字符串"" 这就是为什么在显示时什么也看不到的原因。 请注意,如果要像这样初始化它:

test1 := Test{"a"}

输出为:

&{a}

让我们来看第二个例子:

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

第一行是简短的变量声明 ,将从右侧表达式推断出test2类型。 右边的表达式是一个索引表达式 ,索引一个地图。 它的类型将是映射的值类型,并且由于Models类型是map[string]interface{} ,因此test2类型将是interface{}

到现在为止还挺好。 但是,当您尝试像fmt.Printf("%v", &test2)一样打印时会发生什么? 您传递了一个指向test2的指针,该指针的类型为interface{} ,因此传递的类型为*interface{} ,并且由于它与interface{} ,因此它将被包装在另一个interface{}值中。

因此,传递给fmt.Printf()interface{}值,将*interface{}值包装为test2变量的地址。

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

%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 ,即:

指针:

 %p base 16 notation, with leading 0x 

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

0x1040a160

要从test2获取结构,可以使用类型断言 因此它应该是这样的:

t2 := Models["test"]
test2 := t2.(Test) // test2 is of type Test

test2具有与test1相同的类型,并且在打印时将产生相同的结果。 Go Playground上尝试一下。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM