Go 方法

什么是方法:

方法其实就是一个函数,在func这个关键字和方法名中间加入了一个特殊的接收器类型,接收器可以是结构体类型或者是非结构体类型,接收器是可以在方法的内部访问的。

下面就是创建一个方法的语法:

Go 复制代码
func (t Tpye) methodName(parameter list) { }

上面的代码片段创建了一个接收器类型为Type的方法 methodName

示例:

在Employee结构体类型上创建一个displaySalary方法,displaySalart()方法在方法的内部访问了接收器e Employee

Go 复制代码
package main

import (
    "fmt"
)

type Employee struct {
    name     string
    salary   int
    currency string
}

func (e Employee) displaySalary() {
    fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}

func main() {
    employ1 := Employee{
        name:     "wang",
        salary:   5000,
        currency: "$",
    }
    employ1.displaySalary()
}

输出:

Go 复制代码
Salary of wang is $5000

为什么已经有函数了还需要方法:

将上面的例子改写成函数:

Go 复制代码
package main

import (
    "fmt"
)

type Employee struct {
    name     string
    salary   int
    currency string
}

func displaySalary(e Employee) {
    fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}

func main() {
    employ1 := Employee{
        name:     "wang",
        salary:   5000,
        currency: "$",
    }
    displaySalary(employ1)
}

输出:

Go 复制代码
Salary of wang is $5000

在上面的程序中,displaySalart 方法被转化为一个函数,Employee 结构体被当做参数传递给它,这个程序也产生完全相同的输出

为什么需要方法,有几个原因:

1、Go 不是纯粹的面向对象的编程语言,而且Go不支持类,因此,基于类型的方法是一种实现和类相似行为的途径。

2、相同的名字的方法可以定义在不同类型上,而相同名字的函数是不允许的。

指针接收器和值接收器

GO 方法里面还可以创建指针接收器的方法,值接收器和指针接收器的区别在于,在指针接收器的方法内部的改变对于调用者是可见的,然而值接收器的情况不是这样的

理解:值接收器传递的只是一个值,而指针接收器传递的是一个地址,指向该值的地址

如何选择指针接收器还是值接收器:

1、修改接收器状态:如果方法需要修改接收器的状态,Name通常应该使用指针接收器,这是因为指针接收器可以直接修改接收器指向的对象,而值接收器只是接收对象的副本,对其修改不会影响原始对象。

2、避免值拷贝:如果接收器的类型是较大的结构体或包含了大量数据的类型,而方法不需要修改接收器状态,但需要读取接收器的属性,那么应该考虑使用指针接收器,这可以避免在方法调用时发生不必要的值拷贝,提高程序的性能

3、一致性:如果在类型的方法中有一些方法需要修改接收器状态,而其他方法只是需要读取接收器的属性,那么应该保持一致性,统一使用指针接收器。

4、可空类型:如果类型的零值是合法的,并且在类型的实例在某些情况下可能为nil,那么应该使用指针接收器,这样可以更好处理nil接收器的情况,避免因为nil接收器调用方法而引发panic

示例:

Go 复制代码
package main

import (
    "fmt"
)

type Employee struct {
    name string
    age  int
}

// 使用值接收器的方法
func (e Employee) changeName(newName string) {
    e.name = newName
}

// 使用指针接收器的方法
func (e *Employee) changeAge(newAge int) {
    e.age = newAge
}

func main() {
    e := Employee{
        name: "wang",
        age:  20,
    }
    fmt.Printf("Employee name before change: %s", e.name)
    e.changeName("zhang")
    fmt.Printf("\nEmployee name after change: %s", e.name)
    fmt.Printf("\n\nEmployee age before change: %d", e.age)
    (&e).changeAge(21)
    fmt.Printf("\nEmployee age after change: %d", e.age)
}

输出:

Go 复制代码
Employee name before change: wang 
Employee name after change: wang 
Employee age before change: 20 
Employee age after change: 21

在上面的程序中,changeName方法有一个值接收器(e Employee),而changeAge 方法有一个指针接收器(e *Employee). 在changeName 方法中对Employee结构体的字段name所做的改变对调用者是不可见的,因此在程序调用e.chanName("zhang")这个方法前后打印出相同的名字,由于changeAge方法值使用指针(e *Employee)接收器的,所以在调用(&e).changeAge方法对age字段做出的改变对调用者将是可见的。

在上面的程序里使用了 (&e).changeAge(21)来调用changeAge方法,由于changeAge方法有一个指针接收器,所以使用(&e)来调用这个方法,其实没有这个必要,Go语言让我们可以直接使用e.changeAge(21),会被自动解释为 (&e).changeAge(21)

在方法中使用指针接收器和在函数中使用指针参数

和值参数类似,函数使用指针参数只接受指针,而使用指针接收器的方法可以使用值接收器和指针接收器

示例:

Go 复制代码
package main

import (
    "fmt"
)

type rectangle struct {
    length int
    width  int
}

func perimeter(r *rectangle) {
    fmt.Println("perimeter function output:", 2*(r.length+r.width))
}

func (r *rectangle) perimeter() {
    fmt.Println("perimeter method output:", 2*(r.length+r.width))
}

func main() {
    r := rectangle{
        length: 10,
        width:  5,
    }
    p := &r
    perimeter(p)
    p.perimeter()
    r.perimeter()
}

输出:

Go 复制代码
perimeter function output: 30 
perimeter method output: 30 
perimeter method output: 30

我们通过值接收器 r 来调用有指针接收器的方法 perimeter。这是被允许的,为了方便Go语言把代码 r.perimeter() 解释为 (&r).perimeter()。

在非结构体上的方法

Go 复制代码
package main

import (
    "fmt"
)

type myInt int

func (a myInt) add(b myInt) myInt {
    return a + b
}

func main() {
    num1 := myInt(5)
    num2 := myInt(10)
    sum := num1.add(num2)
    fmt.Println("Sum is", sum)
}

上面的程序中,为int类型创建了一个类型别名myInt,定义了一个以myInt为接收器的方法add

输出:

Go 复制代码
Sum is 15

参考:

Go 系列教程 ------ 17. 方法 - Go语言中文网 - Golang中文社区

相关推荐
Yhame.43 分钟前
深入理解 Java 中的 ArrayList 和 List:泛型与动态数组
java·开发语言
mazo_command3 小时前
【MATLAB课设五子棋教程】(附源码)
开发语言·matlab
IT猿手3 小时前
多目标应用(一):多目标麋鹿优化算法(MOEHO)求解10个工程应用,提供完整MATLAB代码
开发语言·人工智能·算法·机器学习·matlab
青春男大3 小时前
java栈--数据结构
java·开发语言·数据结构·学习·eclipse
88号技师3 小时前
几款性能优秀的差分进化算法DE(SaDE、JADE,SHADE,LSHADE、LSHADE_SPACMA、LSHADE_EpSin)-附Matlab免费代码
开发语言·人工智能·算法·matlab·优化算法
Zer0_on3 小时前
数据结构栈和队列
c语言·开发语言·数据结构
一只小bit3 小时前
数据结构之栈,队列,树
c语言·开发语言·数据结构·c++
2401_882727573 小时前
低代码配置式组态软件-BY组态
前端·后端·物联网·低代码·前端框架
一个没有本领的人4 小时前
win11+matlab2021a配置C-COT
c语言·开发语言·matlab·目标跟踪
一只自律的鸡4 小时前
C项目 天天酷跑(下篇)
c语言·开发语言