Go Receiver Function like Class Method

像 Class Method 的奇特 Go Receiver Function

Go Receiver Function

第一次看到 Go 的 Receiver Function 会觉得这是啥怪语法,函数名前面还能接收参数?

type User struct {
name string
}
// receiver function
func (u User) Greet() {
fmt.Println("Hello, my name is", u.name)
}
func main() {
u := User{name: "Riceball"}
u.Greet()
}

Go 语言提倡「Composition over inheritance」(组合优于继承),并极力追求代码的简洁性,以此规避 class-based OOP 所带来的复杂性。因此,Go 并不直接提供继承机制,而是通过以下三个核心要素,来达到类似 OOP 的模式:

  • Structs: 用于定义数据的结构。
  • Receiver Functions(Method): 用于替自定义类型(包括 struct、基于内建类型的自定义类型等)定义相关联的方法。
  • Interfaces: 用于实现多型(polymorphism)。

其他语言相同范例

JavaScript

const user = {
name: "Riceball",
greet() {
console.log("Hello, my name is", this.name)
}
}
user.greet()

Java

class User {
private String name;
public User(String name) {
this.name = name;
}
public void greet() {
System.out.println("Hello, my name is " + this.name);
}
}
public class Main {
public static void main(String[] args) {
User u = new User("Riceball");
u.greet(); // Hello, my name is Riceball
}
}

总结

Go 的 Receiver Function 本质上仍然是一个独立的函数,它只是通过特殊的语法,将该函数「绑定」到一个特定的类型上,使其能够以面向对象的风格被调用。这种设计巧妙地平衡了面向对象的封装性与 Go 追求的简洁性。

不过相较于 person.greet("Hi") 我还是更偏好单纯函数 greet("Hi", person) 的思考方式。

  • 一个是函数是数据的一部分。
  • 一个是函数与数据相互独立的。

而在撰写 Go 的思维下两者各夹杂一点,十分奇妙。

延伸阅读