pointers - 传递结构和结构指针有什么区别,它们不是都是指针吗?

标签 pointers go

例如

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。如果您熟悉其他语言中可用的按引用传递范例,您可能希望能够完全修改引用的对象,但这并没有发生。这是因为您正在修改作为参数传递的指针的副本

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

如果您将一个大结构作为参数传递,使用指针会更好,因为它可以节省空间,但您无法保证对象不会发生任何变化。

关于pointers - 传递结构和结构指针有什么区别,它们不是都是指针吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44872739/

相关文章:

time - Go:以 YYYYMMDDHHMMSS 格式获取时间的最佳方式

string - 为什么在Golang中使用逗号和下划线。解释以下代码中的第12行?

go - 将函数拆分为 2 个函数以进行测试覆盖

C 自动扩展指针数组

c - 将矩阵传递给 C 中的方法

c++ - 递归删除链表会导致堆栈溢出吗?

c++ - 为 C++ 中的类提供动态数组的默认值

c++ - 无效* p ...; if (p > 0) .... 这是未定义的行为吗?

select - break 语句是否从 switch/select 中断?

passwords - 去吧,基本的访问认证