package main

import "fmt"

// 定义一个 Person 结构体
type Person struct {
	Name string
	Age  int
}

// ========== 值接收者方法 ==========
func (p Person) SayHello() {
	fmt.Printf("Hello, I'm %s (值接收者)\n", p.Name)
}

// 值接收者无法修改原始结构体字段
func (p Person) SetName(name string) {
	p.Name = name // 修改的是副本！
	fmt.Printf("在值接收者中设置 Name = %s\n", p.Name)
}

// ========== 指针接收者方法 ==========
func (p *Person) SayHelloPtr() {
	fmt.Printf("Hello, I'm %s (指针接收者)\n", p.Name)
}

// 指针接收者可以真正修改原始结构体
func (p *Person) SetNamePtr(name string) {
	p.Name = name // 修改的是原始对象！
	fmt.Printf("在指针接收者中设置 Name = %s\n", p.Name)
}

// ========== 对比调用行为 ==========
func main() {
	fmt.Println("=== 1. 使用值类型变量调用方法 ===")
	p1 := Person{Name: "Alice", Age: 30}
	p1.SayHello()        // OK
	p1.SetName("Alicia") // ❌ 不会改变 p1.Name
	fmt.Printf("调用值接收者 SetName 后，p1.Name = %s\n", p1.Name)

	p1.SayHelloPtr()      // ✅ Go 自动取地址 (&p1)
	p1.SetNamePtr("Anna") // ✅ 真正修改了 p1
	fmt.Printf("调用指针接收者 SetNamePtr 后，p1.Name = %s\n", p1.Name)

	fmt.Println("\n=== 2. 使用指针类型变量调用方法 ===")
	p2 := &Person{Name: "Bob", Age: 25}
	p2.SayHello()    // ✅ Go 自动解引用 (*p2)
	p2.SayHelloPtr() // ✅ 直接调用

	p2.SetName("Bobby") // ❌ 副本修改，无效
	fmt.Printf("调用值接收者 SetName 后，p2.Name = %s\n", p2.Name)

	p2.SetNamePtr("Robert") // ✅ 真正修改
	fmt.Printf("调用指针接收者 SetNamePtr 后，p2.Name = %s\n", p2.Name)

	fmt.Println("\n=== 3. 关键规则总结 ===")
	fmt.Println("- 值接收者：操作副本，不能修改原结构体")
	fmt.Println("- 指针接收者：操作原始数据，可修改")
	fmt.Println("- Go 会自动处理 & 和 * 转换（只要变量可寻址）")
	fmt.Println("- 如果方法需要修改字段，请使用指针接收者！")
}
