Golang中结构体指针与变量的对比

Golang中结构体指针与变量的对比

type Point struct {
	x_value int
	y_value int
}

func changePointX(pt *Point, new_x_value int) {
	pt.x_value = new_x_value                                        <-------------------------------------
}

func updateName(n *string) {
	*n = "wedge"                                                        <-------------------------------------
}

func main() {
	point1 := &Point{1, 2}
	fmt.Printf("point 1: %v\n", point1)
	changePointX(point1, 100)
	fmt.Printf("point 1: %v\n", point1)

	name := "tifa"
	m := &name
	updateName(m)
	fmt.Println(name)
}

大家好, 我想理解为什么当我想更新一个字符串的值时,我使用:

*n = "wedge"

而当我想更新一个结构体的值时,我使用:

pt.x_value = new_x_value

这里 pt.x 开头没有星号 (*) —— 我认为也应该像这样: *pt.x_value = new_x_value <— 但这并不工作,而上面的代码是工作的。

我遗漏了什么?

提前非常感谢。


更多关于Golang中结构体指针与变量的对比的实战教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

非常感谢你们的帮助!!

更多关于Golang中结构体指针与变量的对比的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


edgarlip:

*pt.x_value

这样做行不通,因为需要括号来覆盖运算符优先级 (*pt).x_value,但 @NobbZ 解释了正确的惯用法。

edgarlip:

*pt.x_value

星号会对 pt.x_value 进行解引用,而 pt.x_value 是一个 int 类型,并非指针。

点操作符/字段访问器在必要时会自动进行解引用。

@NobbZ - 那么你答案的关键在于,当我使用 struct.field 时,点号会根据需要自动解引用指针。但让我思考的是,Go 如何决定何时需要以及基于什么来决定?

@mje - 能否请你详细解释一下为什么圆括号能让这个生效?

edgarlip:

但是,想到的是 Go 何时决定需要或不需要解引用,以及基于什么?

如果点号左侧是一个指针,那么为了访问字段,它会被解引用;如果不是,则不会解引用。

根据经验,每当你在 C 语言中使用 -> 时,Go 都会为你解引用。

edgarlip:

能否详细说明为什么圆括号能让这个生效?

因为那样你就强制星号与指针绑定,从而在进行字段访问之前先进行解引用。

在Go语言中,结构体指针和字符串指针的解引用方式不同,这是因为它们的类型特性决定的。让我通过代码示例来解释:

type Point struct {
    x_value int
    y_value int
}

// 对于结构体指针,Go会自动解引用
func changePointX(pt *Point, new_x_value int) {
    // 这里 pt.x_value 是语法糖,等价于 (*pt).x_value
    pt.x_value = new_x_value
    
    // 你也可以显式解引用,两种方式都有效
    (*pt).x_value = new_x_value + 1
}

// 对于字符串指针,需要显式解引用
func updateName(n *string) {
    // 字符串是不可变类型,需要直接修改指针指向的值
    *n = "wedge"
    
    // 下面的代码不会工作,因为字符串没有字段
    // n.something = "wedge"  // 编译错误
}

func main() {
    point1 := &Point{1, 2}
    fmt.Printf("point 1: %v\n", point1)
    changePointX(point1, 100)
    fmt.Printf("point 1: %v\n", point1)
    
    name := "tifa"
    m := &name
    updateName(m)
    fmt.Println(name)
    
    // 更多示例
    var s string = "cloud"
    var p *string = &s
    
    // 字符串指针操作
    *p = "aerith"  // 正确:修改指针指向的值
    fmt.Println(s) // 输出: aerith
    
    // 结构体指针操作对比
    point2 := Point{10, 20}
    ptr2 := &point2
    
    // 两种方式都可以
    ptr2.x_value = 30      // 自动解引用
    (*ptr2).y_value = 40   // 显式解引用
    fmt.Printf("point2: %v\n", point2) // 输出: {30 40}
}

关键区别:

  1. 结构体指针:Go提供了语法糖,pt.x_value 会自动解引用为 (*pt).x_value
  2. 字符串指针:字符串是基本类型,没有字段,必须使用 *n 来解引用修改值

如果你尝试 *pt.x_value,这会被解析为 *(pt.x_value),而 pt.x_value 是一个int值,不能解引用,所以会编译错误。正确的显式写法是 (*pt).x_value,但通常使用简写形式 pt.x_value 即可。

回到顶部