# Golang 方法

Go 语言中同时有函数和方法。一个方法就是一个包含了 接受者 的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。

所有给定类型的方法属于该类型的方法集。

方法只是一个函数,它带有一个特殊的接收器类型,它是在 func 关键字和方法名之间编写的。接收器可以是 struct 类型或非 struct 类型。接收方可以在方法内部访问。

方法能给用户自定义的类型添加新的行为。它和函数的区别在于方法有一个接收者,给一个函数添加一个接收者,那么它就变成了方法。接收者可以是值接收者,也可以是指针接收者。

在调用方法的时候

  • 值类型既可以调用值接收者的方法,也可以调用指针接收者的方法
  • 指针类型既可以调用指针接收者的方法,也可以调用值接收者的方法。

也就是说,不管方法的接收者是什么类型,该类型的值和指针都可以调用,不必严格符合接收者的类型

# 一、Golang 方法声明

基本语法:

// 方法
func (t Type) methodName(parameter list)(return list) {

}

// 函数
func funcName(parameter list)(return list){

}

示例:

package main

import (  
    "fmt"
)

type Employee struct {  
    name     string
    salary   int
    currency string
}

/*
    displaySalary 是 Employee 类型的一个方法
*/
func (e Employee) displaySalary() {  
  	// 方法内部可以访问接收者
    fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}

func main() {  
    emp1 := Employee {
        name:     "Sam Adolf",
        salary:   5000,
        currency: "$",
    }
    emp1.displaySalary() // 可以通过 Employe 类型的示例来调用 displaySalary
}

不同类型的接收者可以有 相同 的方法名:

package main

import (
    "fmt"
    "math"
)

type Rectangle struct {
    width, height float64
}
type Circle struct {
    radius float64
}

func (r Rectangle) area() float64 {
    return r.width * r.height
}
//该 method 属于 Circle 类型对象中的方法
func (c Circle) area() float64 {
    return c.radius * c.radius * math.Pi
}
func main() {
    r1 := Rectangle{12, 2}
    r2 := Rectangle{9, 4}
    c1 := Circle{10}
    c2 := Circle{25}
    fmt.Println("Area of r1 is: ", r1.area())
    fmt.Println("Area of r2 is: ", r2.area())
    fmt.Println("Area of c1 is: ", c1.area())
    fmt.Println("Area of c2 is: ", c2.area())
}

输出:

Area of r1 is:  24
Area of r2 is:  36
Area of c1 is:  314.1592653589793
Area of c2 is:  1963.4954084936207
  • 虽然 method 的名字一模一样,但是如果接收者不一样,那么 method 就不一样
  • method 里面可以访问接收者的字段
  • 调用 method 通过 . 访问,就像 struct 里面访问字段一样

# 二、Golang 方法继承

Golang 中 method 是可以“继承”的,这里的继承跟 Java 中的那种 extends 的继承不是一回事,而是说,如果匿名字段实现了一个 method,那么包含这个匿名字段的 struct 也能调用该 method

# 1. 方法继承

下面代码定义了三个结构体:

  • Human
  • Student
  • Employee

Student 和 Employee 中都有一个 Human 类型的匿名字段。

package main

import "fmt"

type Human struct {
    name  string
    age   int
    phone string
}

type Student struct {
    Human  //匿名字段
    school string
}
type Employee struct {
    Human   //匿名字段
    company string
}

// Human 类型定义的方法
func (h *Human) SayHi() {
    fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}

func main() {
    mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
    sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
  	// 包含匿名字段的结构体也可以调用匿名字段拥有的方法
    mark.SayHi()
    sam.SayHi()
}

输出:

Hi, I am Mark you can call me on 222-222-YYYY
Hi, I am Sam you can call me on 111-888-XXXXCOPY

# 2. 方法重写

如果包含匿名字段的类型有用跟匿名字段拥有的方法的名称重复了,那么就覆盖了,

package main

import "fmt"

type Human struct {
    name  string
    age   int
    phone string
}
type Student struct {
    Human  //匿名字段
    school string
}
type Employee struct {
    Human   //匿名字段
    company string
}

// Human 定义 method
func (h *Human) SayHi() {
    fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}

// Employee 的 method 重写 Human 的 method
func (e *Employee) SayHi() {
    fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
        e.company, e.phone)
}
func main() {
    mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
    sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
    mark.SayHi()
    sam.SayHi()
}

输出:

Hi, I am Mark you can call me on 222-222-YYYY
Hi, I am Sam, I work at Golang Inc. Call me on 111-888-XXXX

可以看到由于 Employee 类型重写了 SayHi 方法,所以调用的是 Employee 类型定义的 SayHi 方法。

上次更新: 7/27/2021, 6:41:10 PM