Go基础:013.Method

71 阅读2分钟

概述

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 中的封装仅在程序包之间有效。 换句话说,你只能隐藏来自其他程序包的实现详细信息,而不能隐藏程序包本身。