结构体方法 #

一、方法概述 #

方法是带有接收者的函数,可以为类型定义行为。

二、方法定义 #

2.1 基本语法 #

go
func (接收者 类型) 方法名(参数) 返回值 {
    // 方法体
}

2.2 示例 #

go
type Person struct {
    Name string
    Age  int
}

func (p Person) SayHello() {
    fmt.Printf("Hello, I'm %s\n", p.Name)
}

func (p Person) GetAge() int {
    return p.Age
}

p := Person{Name: "Alice", Age: 25}
p.SayHello()      // Hello, I'm Alice
fmt.Println(p.GetAge())  // 25

三、值接收者 #

3.1 定义 #

go
func (p Person) SetName(name string) {
    p.Name = name  // 修改的是副本
}

p := Person{Name: "Alice"}
p.SetName("Bob")
fmt.Println(p.Name)  // Alice(未改变)

3.2 特点 #

  • 方法内修改不影响原值
  • 适合不修改状态的方法

3.3 适用场景 #

go
func (p Person) GetName() string {
    return p.Name
}

func (p Person) IsAdult() bool {
    return p.Age >= 18
}

四、指针接收者 #

4.1 定义 #

go
func (p *Person) SetName(name string) {
    p.Name = name  // 修改原值
}

p := &Person{Name: "Alice"}
p.SetName("Bob")
fmt.Println(p.Name)  // Bob

4.2 自动转换 #

Go会自动处理值和指针的转换:

go
p := Person{Name: "Alice"}
p.SetName("Bob")  // 自动转换为 (&p).SetName("Bob")

p2 := &Person{Name: "Alice"}
p2.GetName()  // 自动转换为 (*p2).GetName()

4.3 适用场景 #

  • 需要修改接收者
  • 结构体较大,避免复制
  • 保持一致性
go
func (p *Person) Birthday() {
    p.Age++
}

func (p *Person) SetAddress(addr string) {
    p.Address = addr
}

五、方法集 #

5.1 规则 #

接收者类型 值调用 指针调用
值接收者
指针接收者 ✓(自动转换)

5.2 示例 #

go
type Counter struct {
    value int
}

func (c Counter) Value() int {
    return c.value
}

func (c *Counter) Increment() {
    c.value++
}

func main() {
    c := Counter{value: 0}
    c.Increment()      // 自动转换
    fmt.Println(c.Value())  // 1
    
    p := &Counter{value: 0}
    p.Increment()
    fmt.Println(p.Value())  // 1
}

5.3 接口实现 #

接口实现时要注意方法集:

go
type Incrementer interface {
    Increment()
}

type Counter struct {
    value int
}

func (c *Counter) Increment() {
    c.value++
}

func main() {
    var i Incrementer = &Counter{}  // 正确
    // var i Incrementer = Counter{}  // 错误:Counter没有实现Increment
}

六、方法继承 #

6.1 匿名嵌入 #

go
type Animal struct {
    Name string
}

func (a Animal) Speak() {
    fmt.Println("Some sound")
}

type Dog struct {
    Animal
}

func main() {
    d := Dog{Animal{Name: "Buddy"}}
    d.Speak()  // Some sound
}

6.2 方法重写 #

go
func (d Dog) Speak() {
    fmt.Println("Woof!")
}

func main() {
    d := Dog{Animal{Name: "Buddy"}}
    d.Speak()  // Woof!
    d.Animal.Speak()  // Some sound
}

七、方法值与表达式 #

7.1 方法值 #

go
p := Person{Name: "Alice"}

hello := p.SayHello  // 方法值
hello()  // Hello, I'm Alice

7.2 方法表达式 #

go
hello := Person.SayHello  // 方法表达式
hello(p)  // Hello, I'm Alice

setName := (*Person).SetName
setName(&p, "Bob")

7.3 作为参数 #

go
func process(p Person, f func(Person) string) {
    fmt.Println(f(p))
}

p := Person{Name: "Alice"}
process(p, Person.GetName)

八、实际应用 #

8.1 链式调用 #

go
type Builder struct {
    value strings.Builder
}

func (b *Builder) Write(s string) *Builder {
    b.value.WriteString(s)
    return b
}

func (b *Builder) WriteLine(s string) *Builder {
    b.value.WriteString(s)
    b.value.WriteString("\n")
    return b
}

func (b *Builder) String() string {
    return b.value.String()
}

func main() {
    b := &Builder{}
    result := b.Write("Hello").Write(" ").WriteLine("World").String()
    fmt.Println(result)
}

8.2 验证方法 #

go
type User struct {
    Name  string
    Email string
    Age   int
}

func (u User) Validate() error {
    if u.Name == "" {
        return errors.New("name is required")
    }
    if !strings.Contains(u.Email, "@") {
        return errors.New("invalid email")
    }
    if u.Age < 0 {
        return errors.New("invalid age")
    }
    return nil
}

8.3 状态管理 #

go
type Counter struct {
    value int
    mu    sync.Mutex
}

func (c *Counter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.value++
}

func (c *Counter) Value() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.value
}

九、最佳实践 #

9.1 选择接收者类型 #

  • 需要修改:指针接收者
  • 结构体大:指针接收者
  • 只读操作:值接收者
  • 一致性:整个类型统一使用一种

9.2 方法命名 #

go
// 好
func (p *Person) SetName(name string) {}
func (p Person) GetName() string {}
func (p Person) IsAdult() bool {}

// 不好
func (p *Person) set_name(name string) {}

9.3 避免大结构体复制 #

go
type LargeStruct struct {
    data [10000]int
}

// 好:指针接收者
func (l *LargeStruct) Process() {}

// 不好:值接收者,复制开销大
func (l LargeStruct) Process() {}

十、总结 #

方法要点:

特性 说明
值接收者 操作副本
指针接收者 操作原值
自动转换 Go自动处理值/指针转换
方法集 影响接口实现

关键点:

  1. 接收者类型:根据是否需要修改选择
  2. 一致性:同一类型的所有方法使用相同接收者类型
  3. 方法值:方法可以赋值给变量
  4. 方法继承:匿名嵌入继承方法
  5. 接口实现:注意方法集规则

准备好学习结构体嵌套了吗?让我们进入下一章!

最后更新:2026-03-26