繁体   English   中英

传递结构体和结构体的指针有什么区别,它们不是两个指针吗?

[英]What is the difference between passing a struct and pointer of the struct, are they not both pointers?

例如

var myStructRef *Vertex
var myStruct Vertex
myStructRef = &Vertex{2, 3}
myStruct = Vertex{2, 3}

fmt.Println(myStructRef)
fmt.Println(myStruct)
changeByReferenceStruct(myStructRef)
changeByValueStruct(myStruct)
fmt.Println(myStructRef)
fmt.Println(myStruct)

并且

func changeByValueStruct(myStruct Vertex) {
    myStruct.X = 5
    fmt.Println(myStruct)
}


func changeByReferenceStruct(myStruct *Vertex) {
    myStruct.X = 7
    fmt.Println(myStruct)
}

myStructRef *VertexmyStruct Vertex不是指向结构本身的指针吗? 为什么在修改函数中的结构体时会出现行为差异?

是golang创造一个新的结构changeByValueStruct当它解决了参数?

当您将指针作为参数传递时,幕后发生的是创建该指针的副本并将其传递给底层函数。 它不应该与传递引用混淆。

让我们看一个例子来更好地理解它:

package main

import (
    "fmt"
)

type Point struct {
    x int
    y int
}

func (p Point) String() string {
    return fmt.Sprintf("(%d, %d)", p.x, p.y)
}

func modifyValue(point Point) {
    point.x += 10
}

func modifyPointer(point *Point) {
    point.x = 5
    point.y = 5
}

func modifyReference(point *Point) {
    point = &Point{5, 5}
}

func main() {
    p := Point{0, 0}
    fmt.Println(p) // prints (0, 0)
    
    modifyValue(p)
    fmt.Println(p) // prints (0, 0)
    
    modifyPointer(&p)
    fmt.Println(p) // prints (5, 5)
    
    p = Point{0, 0}
    modifyReference(&p)
    fmt.Println(p) // prints (0, 0)
}

modifyValue函数内部发生的事情是修改了一个完全不同的 Point 结构实例,因此调用该函数时传递的值不受影响。

在第二个示例中,传递了指向结构的指针,因此可以以从外部可见的方式修改结构的字段。

最有趣的一点是由最后一个函数modifyReference 提出的 如果您熟悉其他语言中可用的按引用传递范例,您可能希望能够完全修改引用的对象,但这不会发生。 这是因为您正在修改作为参数传递的指针的副本

你可能想知道,如果一切都是按值传递的,你应该什么时候传递指针,什么时候传递值。 传递值向调用函数保证传递的结构不会受到任何更改,因此当您需要此行为时,请选择该值。 这样做的缺点是制作了整个对象的副本,如果它太大,内存就会成为问题。

如果你传递一个大结构作为参数,使用指针更好,因为它节省空间,但你失去了对象不会遭受任何更改的保证。

将结构传递给函数参数会复制值。 并且传递结构指针不会。 所以传递结构不能更新字段值。

package main

import (
    "fmt"
)

type Foo struct {
    value int
}

func PassStruct(foo Foo) {
    foo.value = 1
}

func PassStructPointer(foo *Foo) {
    foo.value = 1
}

func main() {
    var foo Foo

    fmt.Printf("before PassStruct: %v\n", foo.value)
    PassStruct(foo)
    fmt.Printf("after PassStruct: %v\n", foo.value)

    fmt.Printf("before PassStructPointer: %v\n", foo.value)
    PassStructPointer(&foo)
    fmt.Printf("after PassStructPointer: %v\n", foo.value)
}

https://play.golang.org/p/AM__JwyaJa

暂无
暂无

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

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