Go语言15-高级-面向对象——方法

1.Go语言面向对象编程特性

Go语言没有封装,继承,多态这些概念,但它通过以下方式实现了这些特性。

特性实现方式
封装通过方法实现
继承通过匿名字段实现
多态通过接口实现

2.Go语言方法

封装是指将对象运行所需的资源封装再程序对象中。而Go语言通过方法实现封装。

2.1定义格式

方法,本质上是一个函数。与普通函数的格式有一点不同,它在关键字func和方法名中间加入了一个特殊的接收器类型。其格式如下:

//    接收器      方法名      参数列表
func (t Type) methodName(parameter list) {
    /*方法体代码*/
}

注:a.接收者t的名字自定义,它可以被方法的内部内容访问;

b.接受者即可以是结构体类型,也可以是非结构体类型。

2.2接收者类型

2.2.1结构体类型

由于接收者可以被方法内部内容访问,当接收者类型为结构体时,方法内部也可以访问结构体的成员变量,访问格式为:

接收者.结构体成员变量名

(&接收者).结构体成员变量名

调用此方法的格式为:

结构体类型变量名.方法名()

(&结构体类型变量名).方法名()

package main

import "fmt"

type Animal struct {
	name  string
	sex   byte
	color string
}

/*接收者:a;接收者类型:Animal;方法名:printInfo*/
func (a Animal) printInfo() {
	fmt.Printf("name=%s, sex=%c, color=%s\n", a.name, (&a).sex, a.color)
}
func main() {
	p := Animal{"wangcai", 'm', "white"}
	p.printInfo()    //调用格式:结构体变量名.方法名
	(&p).printInfo() //调用格式:(&结构体变量名).方法名
}

2.2.2基础类型

接收者类型为结构体类型,定义的结构体和定义在结构体上的方法同属一个main包,所以结构体类型可以直接使用方法。

基础类型在使用方法前先对基础类型声明类型别名。

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)
}

2.3 值语义和引用语义

值语义和引用语义,指的是接收者类型分别是值类型和指针类型。

接收者类型说明
值类型不论传递到接收者的参数类型是值类型还是指针类型,方法都会将参数类型转换为值类型,在方法内部对值类型的接收者进行改变,方法调用时不会发生改变。
指针类型不论传递到接收者的参数是值类型还是指针类型,方法都会将参数类型转换为指针类型,在方法内部对指针类型的接收者进行改变,方法调用时发生改变。
package main

import "fmt"

type Animal struct {
	name  string
	age   int
	color string
}

//接收者类型是值类型
func (a Animal) valueChange(newName, newColor string) {
	a.name = newName
	(&a).color = newColor
}

//接收者类型是指针类型
func (b *Animal) pointerChange(newName, newColor string) {
	b.name = newName
	(*b).color = newColor
}

func main() {
	p := Animal{"xiaogou", 3, "white"}
	/*当接收者类型是值类型,不论传递到接收者的参数类型是值类型还是指针类型,
	方法都会将参数类型转换为值类型,在方法内部对值类型的接收者进行改变,
	方法调用时相关元素没有改变*/
	p.valueChange("wangcai", "huangse")
	fmt.Println(p)
	(&p).valueChange("旺财", "黄色")
	fmt.Println(p)
	/*当接收者类型是引用类型,不论传递到接收者的参数类型是值类型还是指针类型,
	方法调用时相关元素发生改变*/
	(&p).pointerChange("xiaoqiang", "blue")
	fmt.Println(p)
	p.pointerChange("小强", "蓝色")
	fmt.Println(p)
}

注:这和其他语言的类不一样,其他语言类的方法改变类的成员变量直接生效。Go 成员变量是否改变,和其方法的接收器类型有关,只有接收器类型为引用时,才会对接收器的成员变量有效。

3.方法和函数的区别

类型函数方法
语法格式func A(a int,)(c int){
    return a+1
}

type myint int

func (a myint)A()(c int){
    return a+1
}

传入对象形参值接收与自己类型相同的实参。接收者类型为值类型或者指针类型的方法均可以接受值类型或者指针类型的传入对象。
同名函数不允许同名。同名的方法可以定义在不同类型的接收者。

3.1接收者为值类型的方法和参数为值类型的函数测区别

3.1.1 接收者为值类型的方法和参数为值类型的函数的区别

package main

import "fmt"

type Animal struct {
	name  string
	age   int
	color string
}

func functionValue(a Animal) { //函数参数是值类型
	a.name = "wangcai"
	(&a).color = "huangse"
}
func (b Animal) methodValue() { //接收者类型是值类型
	b.name = "xiaoqiang"
	(&b).color = "blue"
}

func main() {
	p := Animal{"xiaogou", 3, "white"}
	/*当函数参数是值类型,实参只能是值类型*/
	functionValue(p)
	fmt.Println(p)
	//functionValue(&p) //不可以

	/*当接收者类型是值类型,对值类型、指针类型的传入对象均可以接受,方法调用时相关元素没有改变*/
	(&p).methodValue()
	fmt.Println(p)
	p.methodValue()
	fmt.Println(p)
}

3.1.2 接收者为引用类型的方法和参数为引用类型的函数的区别

package main

import "fmt"

type Animal struct {
	name  string
	age   int
	color string
}

//函数参数是指针类型
func functionPointer(a *Animal) {
	a.name = "wangcai"
	(*a).color = "huangse"
}

//接收者类型是指针类型
func (b *Animal) methodPointer() {
	b.name = "xiaoqiang"
	(*b).color = "blue"
}

func main() {
	p := Animal{"xiaogou", 3, "white"}
	/*函数参数是指针类型,只能接受指针类型的实参*/
	functionPointer(&p)
	fmt.Println(p)
	//functionPointer(p)
	/*当接收者类型是指针类型,对值类型、指针类型的传入对象均可以接受,方法调用时相关成员发生改变*/
	(&p).methodPointer()
	fmt.Println(p)
	p.methodPointer()
	fmt.Println(p)
}

3.2 方法和函数在是否可以同名方面的区别

package main

import "fmt"

type Animal struct {
	name  string
	age   int
	color string
}
type animal struct {
	name  string
	age   int
	color string
}

func (A Animal) printInfo() {
	fmt.Printf("p=%v,p的地址为:%p\n", A, &A)
}

//和上面方法的接收者类型不同,但方法名相同
func (a animal) printInfo() {
	fmt.Printf("p=%v,p的地址为:%p\n", a, &a)
}
func printInfo(A Animal) { //函数名可以和方法名相同
	fmt.Printf("p=%v,p	%p\n", A, &A)
}

//一个包内部不能出现两个相同的函数名,参数不同也不可以
//func printInfo(a animal) {
// fmt.Printf("p=%v,p的地址为:%p\n", a, &a)
//}

func main() {
	A := Animal{"xiaogou", 3, "white"}
	A.printInfo()
	a := animal{"小狗", 3, "白色"}
	a.printInfo()
	printInfo(A)
}

4.方法值和方法表达式

根据调用者不同,方法分为两种表现形式:方法值和方法表达式。两者都可以像普通函数那样赋值和传参,区别在于方法值需要绑定实例,而方法表达式则需要显式传参。

4.1方法值

方法值进行赋值和传参时,方法值需要绑定实例。

4.2方法表达式

方法表达式进行赋值和传参时必须显式传参。

方法值:

package main

import "fmt"

type Animal struct {
	name  string
	age   int
	color string
}

//接收者类型是值类型
func (a Animal) printInfoValue() {
	fmt.Printf("p=%v,p的地址为:%p\n", a, &a)
}

//接收者指针类型
func (a *Animal) printInfoPointer() {
	fmt.Printf("p=%v,p的地址为:%p\n", a, a)
}
func main() {
	p := Animal{"xiaogou", 3, "white"}
	/*方法接收者为值类型*/
	p.printInfoValue()
	pFunc1 := p.printInfoValue //方法值进行赋值,绑定实例p
	fmt.Printf("%T\n", pFunc1) //func()
	pFunc1()
	(&p).printInfoValue()
	pFunc2 := (&p).printInfoValue //传入参数&p
	pFunc2()
	/*方法接收器为指针类型*/
	p.printInfoPointer()
	pFunc3 := p.printInfoPointer
	pFunc3()
	(&p).printInfoPointer()
	pFunc4 := (&p).printInfoPointer
	pFunc4()
}

方法表达式

package main

import "fmt"

type Animal struct {
	name  string
	age   int
	color string
}

//接收者类型是值类型
func (a Animal) printInfoValue() {
	fmt.Printf("p=%v,p的地址为:%p\n", a, &a)
}

//接收者指针类型
func (a *Animal) printInfoPointer() {
	fmt.Printf("p=%v,p的地址为:%p\n", a, a)
}
func main() {
	p := Animal{"xiaogou", 3, "white"}
	pFunc1 := Animal.printInfoValue //方法值进行赋值,绑定实例p
	fmt.Printf("%T\n", pFunc1)      //func(main.Animal)
	pFunc1(p)
	pFunc2 := (*Animal).printInfoValue //传入参数&p
	pFunc2(&p)
	/*接收者是指针类型,用方法表达式进行传递时,
	接收者只能接受指针类型的传入对象*/
	//pFunc3 := Animal.printInfoPointer //不接受值类型
	//pFunc3(p)
	pFunc4 := (*Animal).printInfoPointer
	pFunc4(&p) //*Animal是指针类型,传入的&p是指针类型
}

5.方法的延迟调用

在方法调用之前加上defer,则对方法延迟调用

package main

import "fmt"

type Animal struct {
	name  string
	sex   byte
	color string
}

func (a Animal) printInfo() {
	fmt.Printf("name=%s, sex=%c, color=%s\n", a.name, a.sex, a.color)
}
func main() {
	p := Animal{"wangcai", 'm', "white"}
	defer p.printInfo() //在方法调用之前家defer
	fmt.Println("main")
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值