Golang 中的函数与方法

文章目录

这篇文章将描述 Go 中函数和方法之间的主要区别,以及何时使用它们最好。

函数和方法都在 Go 中被广泛使用,以提供抽象并使我们的程序更易于阅读和理解。从表面上看,函数和方法看起来很相似,但存在一些重要的语义差异,这些差异会对代码的可读性产生很大影响。

句法

声明语法

通过指定参数类型、返回值和函数体来声明函数:

type Person struct {
  Name string
  Age int
}

// 这个函数返回一个新的 `Person` 实例
func NewPerson(name string, age int) *Person {
  return &Person{
    Name: name,
    Age: age,
  }
}

而方法则是通过额外指定“接收者”(即 OOP 中该方法所属的“类”)来声明:

// `Person` 指针类型是 `isAdult` 方法的接收者
func (p *Person) isAdult() bool {
  return p.Age > 18
}

在上面的方法声明中,我们在 *Person 类型上声明了 isAdult 方法。

执行语法

函数使用指定的参数独立调用,方法则根据其接收者的类型调用:

p := NewPerson("John", 21)

fmt.Println(p.isAdult())
// true

互换性

函数和方法理论上可以互换。例如,我们可以将 isAdult 方法变成一个函数,并将 NewPerson 函数作为一个方法:

type PersonFactory struct {}

// `NewPerson` 现在是 `PersonFactory` 结构的一个方法
func (p *PersonFactory) NewPerson(name string, age int) *Person {
  return &Person{
    Name: name,
    Age: age,
  }
}

// `isAdult` 现在是一个函数,我们将 `Person` 作为参数传递
func isAdult(p *Person) bool {
  return p.Age > 18
}

这种情况下的执行语法看起来有点奇怪:

factory := &PersonFactory{}

p := factory.NewPerson("John", 21)

fmt.Println(isAdult(p))
// true

使用场景

让我们来看看 Go 应用程序中遇到的一些常见用例,以及用于每个用例的适当抽象(函数或方法):

方法链

方法的一个非常有用的特性是能够将它们链接在一起,同时仍然保持代码干净。让我们举一个使用方法链设置 Person 的一些属性的例子:

type Person struct {
	Name string
	Age  int
}

func (p *Person) withName(name string) *Person {
	p.Name = name
	return p
}

func (p *Person) withAge(age int) *Person {
	p.Age = age
	return p
}

func main() {
	p := &Person{}

	p = p.withName("John").withAge(21)

  fmt.Println(*p)
  // {John 21}
}

如果我们使用函数来做同样的事,它看起来会很糟糕:

p = withName(withAge(p, 18), "John")

有状态与无状态执行

这里的“无状态”意味着任何一段代码总是为相同的输入返回相同的输出

在互换性示例中,我们看到了使用 PersonFactory 对象来创建 person 的新实例。事实证明,这是一种反模式,应该避免。

对于无状态执行,最好使用之前声明的 NewPerson 之类的函数。

而对于有状态执行,如果发现一个函数读取并修改了许多特定类型的值,那么它可能就该使用该类型的方法。

语义

语义是指代码的阅读方式。如果您用口语大声朗读代码,那么哪种方式更有意义?

让我们看一下 isAdult 的函数和方法实现:

customer := NewPerson("John", 21)

// 方法
customer.isAdult()

// 函数
isAdult(customer)

对于询问“客户是成年人吗?”这里的 isAdult(customer)customer.isAdult() 相比,读起来更好。


也可以看看


全国大流量卡免费领

19元月租ㆍ超值优惠ㆍ长期套餐ㆍ免费包邮ㆍ官方正品