概述
Go 中的方法是一种特殊类型的函数,但存在一个简单的区别:你必须在函数名称之前加入一个额外的参数。 此附加参数称为接收方。
Go 中的这一方法类似于在其他编程语言中创建类,因为它允许你实现面向对象编程 (OOP) 模型中的某些功能,例如嵌入、重载和封装。
声明方法
通过添加方法你可以将行为添加到你所创建的结构中。
但是,在声明方法之前,必须先创建结构。
type triangle struct {
size int
}
func (t triangle) perimeter() int {
return t.size * 3
}
func main() {
t := triangle{3}
fmt.Println("Perimeter:", t.perimeter())
}
方法中的指针
有时,方法需要更新变量,或者,如果参数太大,则可能需要避免复制它。 在遇到此类情况时,你需要使用指针传递变量的地址。
func (t *triangle) doubleSize() {
t.size *= 2
}
func main() {
t := triangle{3}
t.doubleSize()
fmt.Println("Size:", t.size)
fmt.Println("Perimeter:", t.perimeter())
}
如果方法仅可访问接收方的信息,则不需要在接收方变量中使用指针。 但是,依据 Go 的约定,如果结构的任何方法具有指针接收方,则此结构的所有方法都必须具有指针接收方,即使某个方法不需要也是如此。
声明其他类型的方法
方法的一个关键方面在于,需要为任何类型定义方法,而不只是针对自定义类型(如结构)进行定义。 但是,你不能通过属于其他包的类型来定义结构。 因此,不能在基本类型(如 string)上创建方法。
尽管如此,你仍然可以利用一点技巧,基于基本类型创建自定义类型,然后将其用作基本类型。
package main
import (
"fmt"
"strings"
)
type upperstring string
func (s upperstring) Upper() string {
return strings.ToUpper(string(s))
}
func main() {
s := upperstring("Learning Go!")
fmt.Println(s)
fmt.Println(s.Upper())
}
嵌入方法
type coloredTriangle struct {
triangle
color string
}
func main() {
t := coloredTriangle{triangle{3}, "blue"}
fmt.Println("Size:", t.size)
fmt.Println("Perimeter", t.perimeter())
}
实际上,Go 编译器会通过创建如下的包装器方法来推广 perimeter() 方法
func (t coloredTriangle) perimeter() int {
return t.triangle.perimeter()
}
重载方法
func (t coloredTriangle) perimeter() int {
return t.size * 3 * 2
}
func main() {
t := coloredTriangle{triangle{3}, "blue"}
fmt.Println("Size:", t.size)
fmt.Println("Perimeter", t.perimeter())
fmt.Println("Perimeter (colored)", t.perimeter())
fmt.Println("Perimeter (normal)", t.triangle.perimeter())
}
方法中的封装
在 Go 中,只需使用大写标识符,即可公开方法,使用非大写的标识符将方法设为私有方法。
Go 中的封装仅在程序包之间有效。 换句话说,你只能隐藏来自其他程序包的实现详细信息,而不能隐藏程序包本身。