【go进阶】方法

为什么引入方法?

Golang 中的方法是作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型, 都可以有方法,而不仅仅是 struct。

在Go语言中,引入方法是为了实现类型相关的行为和操作。方法是与特定类型关联的函数,它们允许在类型上定义和调用特定的行为。

使用方法的常见原因和优势:

  • 封装与信息隐藏:通过方法,可以将类型的内部实现细节隐藏起来,只暴露必要的公共接口。这提供了封装的能力,使得类型的使用者只需要关注公开的方法和属性,而不需要了解底层实现。

  • 类型相关的操作:方法允许在类型上定义特定的操作。通过将方法与类型相关联,可以更自然地表达类型所具有的行为,增强代码的可读性和可理解性。

  • 代码组织和可维护性:方法可以将与类型相关的逻辑和操作集中在一起,更好地组织代码。这使得代码更加模块化、可维护和可扩展。

  • 类似面向对象编程的特性:方法使得类型可以具有类似于面向对象编程的特性,如封装、继承和多态。通过在方法中操作类型的数据,可以实现类型的状态管理和行为定义。

  • 代码重用:方法可以在多个类型之间共享和重用。通过在不同类型上定义相同的方法,可以实现相似行为的类型之间的代码共享,减少重复代码的编写。

  • 接口实现:方法在实现接口方面非常有用。通过在类型上定义实现接口所需的方法,可以使类型满足接口的约束,并实现多态的特性。

总体而言,方法是一种非常有用的语言特性,它与类型紧密相关,提供了一种清晰、可读和可维护的方式来定义和调用类型相关的行为。通过使用方法,可以增强代码的可读性、可理解性和可扩展性,同时提供了面向对象编程的一些特性。

方法的声明

func (recevier type) methodName(参数列表) (返回值列表){
方法体
return 返回值
}
  1. 参数列表:表示方法输入
  2. recevier type : 表示这个方法和 type 这个类型进行绑定,或者说该方法作用于 type 类型
  3. receiver type : type 可以是结构体,也可以其它的自定义类型
  4. receiver : 就是 type 类型的一个变量(实例),比如 :Person 结构体 的一个变量(实例)
  5. 返回值列表:表示返回的值,可以多个
  6. 方法主体:表示为了实现某一功能代码块
  7. return 语句不是必须的。

举例

type A struct { 
	Num int
 } 
	
func (a A) test() { 
 	fmt.Println(a.Num) 
 }

对上面的语法的说明

  1. func (a A) test() {} 表示 A 结构体有一方法,方法名为 test
  2. (a A) 体现 test 方法是和 A 类型绑定的方法的声明

方法的调用

func (recevier type) methodName(参数列表) (返回值列表){
方法体
return 返回值
}

调用形式:自定义结构体名.methodName

package main

import (
	"fmt"
)

type Person struct {
	Name string
}

// 给Person结构体添加speak 方法,输出  xxx是一个好人
func (p Person) speak() {
	fmt.Println(p.Name, "是一个goodman~")
}

//给Person结构体添加jisuan 方法,可以计算从 1+..+1000的结果,
//说明方法体内可以函数一样,进行各种运算

func (p Person) jisuan() {
	res := 0
	for i := 1; i <= 1000; i++ {
		res += i
	}
	fmt.Println(p.Name, "计算的结果是=", res)
}

// 给Person结构体jisuan2 方法,该方法可以接收一个参数n,计算从 1+..+n 的结果
func (p Person) jisuan2(n int) {
	res := 0
	for i := 1; i <= n; i++ {
		res += i
	}
	fmt.Println(p.Name, "计算的结果是=", res)
}

// 给Person结构体添加getSum方法,可以计算两个数的和,并返回结果
func (p Person) getSum(n1 int, n2 int) int {
	return n1 + n2
}

// 给Person类型绑定一方法
func (person Person) test() {
	person.Name = "jack"
	fmt.Println("test() name=", person.Name) // 输出jack
}

type Dog struct {
}

func main() {

	var a Person
	a.Name = "tom"
	a.test()                              //调用方法
	fmt.Println("main() a.Name=", a.Name) //输出 tom
	//下面的使用方式都是错误的
	// var dog Dog
	// dog.test()
	// test()

	//调用方法
	a.speak()
	a.jisuan()
	a.jisuan2(20)
	n1 := 10
	n2 := 20
	res := a.getSum(n1, n2)
	fmt.Println("res=", res)
}

只要和方法接收者recevier绑定的类型一致的数据类型都可以调用这个方法;

package main

import (
	"fmt"
)

type integer int

func (i integer) print() {
	fmt.Println("传入的值为=", i)
}
//调用该方法的结构体作为实参传入该方法

// 编写一个方法,可以改变i的值
func (i *integer) change() {
	*i = *i + 1
}

func main() {
	var j integer = 10
	j.print()
	fmt.Println("j.print=", j)
	j.change()
	fmt.Println("j.change=", j)

	//只要和方法接收者recevier绑定的类型一致的数据类型都可以调用这个方法;
	var p integer = 100
	p.print()
	fmt.Println("p.print=", p)
	p.change()
	fmt.Println("p.change=", p)
}

传入的值为 10
j.print= 10
j.change= 11
传入的值为 100
p.print= 100
p.change= 101

方法的传参机制

https://www.bilibili.com/video/BV1ME411Y71o?p=194&spm_id_from=pageDriver&vd_source=de1585eb7b5cc18db8bc86435eb81c0f

方法的调用和传参机制和函数基本一样,不一样的地方是变量调用方法时,该变量本身也会作为一个参数传递到方法(如果变量是值类型,则进行值拷贝,如果变量是引用类型,则进行地质拷贝)

方法的值传递与引用传递

  1. 结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式
  2. 如程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理
package main

import (
	"fmt"
)


type integer int

func (i integer) print() {
	fmt.Println("传入的值为", i)
}

// 值传递,传入的i是多少,传出去还是多少,这里的输出会+1;但是不会改变传入的值,传入是10,后文再查看还是10
func (i integer) printadd() {
	i = i + 1
	fmt.Println("printadd函数内,传入的值+1 =", i)
}

// 编写一个方法,可以改变i的值
func (i *integer) change() {
	*i = *i + 1
}

func main() {
	var j integer = 10
	j.print()
	fmt.Println("j.print=", j)
	j.printadd()
	fmt.Println("执行完j.printadd后,j的值为=", j)
	j.change()
	fmt.Println("j.change=", j)

	var p integer = 100
	p.print()
	fmt.Println("p.print=", p)
	p.printadd()
	fmt.Println("执行完p.printadd后,p的值为=", p)
	p.change()
	fmt.Println("p.change=", p)
}

传入的值为 100
p.print= 100
printadd函数内,传入的值+1 = 101
执行完p.printadd后,p的值为= 100
p.change= 101

方法的使用细节

  1. Golang 中的方法作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型, 都可以有方法,而不仅仅是 struct, 比如 int , float32 等都可以有方法

  2. 方法的访问范围控制的规则,和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其它包访问。

方法和函数的区别

  1. 调用方式不一样
    函数的调用方式: 函数名(实参列表)
    方法的调用方式: 变量.方法名(实参列表)

  2. 对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然
    对于方法(如 struct 的方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以

  3. 不管调用形式如何,真正决定是值拷贝还是地址拷贝,看这个方法是和哪个类型绑定.

  4. 如果是和值类型,比如 (p Person) , 则是值拷贝, 如果和指针类型,比如是 (p *Person) 则是地址拷贝。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值