Golang初学者问题:结构体、方法与指针的使用

Golang初学者问题:结构体、方法与指针的使用 我正在学习一门Udemy课程,对指针有一个疑问,但老师没有讨论到。

我理解指针、内存地址及其内容。我知道,如果你想就地修改结构体(在此例中),而不是修改副本,可能会需要使用指针。

参考以下代码…

type person struct {
	first string
	last  string
}

func (p *person) changeMeMethod() {
	(*p).first = "Jo"
}

func changeMeFunc(p *person) {
	(*p).first = "Flem"
}

func main() {
	p := person{
		first: "Mac",
		last:  "Kam",
	}
	fmt.Println(p)
	p.changeMeMethod()
	fmt.Println(p)
	changeMeFunc(&p)
	fmt.Println(p)
}

changeMeMethod 中的接收器使用指针有什么实际原因吗?因为该方法已经附加到结构体上,所以不会复制值。

我这样想对吗?


更多关于Golang初学者问题:结构体、方法与指针的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

在Go语言中,我们不会为接收器使用像thisself这样的特殊名称,而是像为任何参数选择名称一样来选择接收器名称。

使用指针作为接收器可以避免复制值,这在需要更新接收器变量或避免复制值时使用,我们通过指针使用变量的地址。

否则:

type person struct {
	first string
	last  string
}

func (p person) changeMeMethod() {
	p.first = "Jo"
}

func changeMeFunc(p person) {
	p.first = "Flem"
}

func main() {
	p := person{
		first: "Mac",
		last:  "Kam",
	}
	fmt.Println(p)
	p.changeMeMethod()
	fmt.Println(p)
	changeMeFunc(p)
	fmt.Println(p)
}
// 输出:
// {Mac Kam}
// {Mac Kam}
// {Mac Kam}

https://play.golang.org/p/2Pdlv2IOxZD

使用指针

type person struct {
	first string
	last  string
}

func (p *person) changeMeMethod() {
	p.first = "Jo"
}

func changeMeFunc(p *person) {
	p.first = "Flem"
}

func main() {
	p := person{
		first: "Mac",
		last:  "Kam",
	}
	fmt.Println(p)
	p.changeMeMethod()
	fmt.Println(p)
	changeMeFunc(&p)
	fmt.Println(p)
}
// 输出:
// {Mac Kam}
// {Jo Kam}
// {Flem Kam}

更多关于Golang初学者问题:结构体、方法与指针的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个很好的问题,触及了Go中方法接收器的核心概念。

你的理解不完全正确。即使方法附加到结构体上,接收器默认也是值传递,会复制整个结构体。在你的例子中,changeMeMethod 使用指针接收器 (p *person) 是必要的,否则你无法修改原始结构体。

让我用代码演示区别:

package main

import "fmt"

type person struct {
	first string
	last  string
}

// 指针接收器 - 可以修改原始结构体
func (p *person) changeMeMethod() {
	p.first = "Jo" // Go会自动解引用,不需要写 (*p).first
}

// 值接收器 - 只能修改副本
func (p person) changeMeMethodValue() {
	p.first = "Copy Modified" // 这只会修改副本
	fmt.Println("Inside value receiver:", p)
}

func main() {
	p := person{
		first: "Mac",
		last:  "Kam",
	}
	
	fmt.Println("Original:", p) // {Mac Kam}
	
	// 值接收器示例
	p.changeMeMethodValue()
	fmt.Println("After value receiver:", p) // 仍然是 {Mac Kam}
	
	// 指针接收器示例
	p.changeMeMethod()
	fmt.Println("After pointer receiver:", p) // {Jo Kam}
	
	// 证明值接收器创建了副本
	p1 := person{first: "A", last: "B"}
	p2 := p1
	p2.first = "C"
	fmt.Println("p1:", p1) // {A B}
	fmt.Println("p2:", p2) // {C B}
}

关键点:

  1. 方法接收器默认是值传递func (p person) method() 会复制整个结构体
  2. 指针接收器避免复制func (p *person) method() 只传递指针(通常8字节)
  3. Go的语法糖:使用 p.first 而不是 (*p).first,编译器会自动处理
  4. 性能考虑:对于大结构体,使用指针接收器更高效

实际使用建议:

// 小结构体或不需要修改时使用值接收器
type Point struct { x, y int }
func (p Point) Distance() float64 { /* 只读操作 */ }

// 需要修改或结构体较大时使用指针接收器
type User struct { /* 多个字段 */ }
func (u *User) UpdateProfile() { /* 修改操作 */ }

在你的代码中,changeMeMethod 必须使用指针接收器才能实际修改 person 实例,否则只会修改方法内的副本。

回到顶部