go語(yǔ)言方法集為類(lèi)型添加方法示例解析
1概述
在面向?qū)ο缶幊讨校粋€(gè)對(duì)象其實(shí)也就是一個(gè)簡(jiǎn)單的值或者一個(gè)變量,在這個(gè)對(duì)象中會(huì)包含一些函數(shù),這種帶有接收者的函數(shù),我們稱(chēng)為方法(method)。本質(zhì)上,一個(gè)方法則是一個(gè)和特殊類(lèi)型關(guān)聯(lián)的函數(shù)。
一個(gè)面向?qū)ο蟮某绦驎?huì)用方法來(lái)表達(dá)其屬性和對(duì)應(yīng)的操作,這樣使用這個(gè)對(duì)象的用戶(hù)就不需要直接去操作對(duì)象,而是借助方法來(lái)做這些事情。
在Go語(yǔ)言中,可以給任意自定義類(lèi)型(包括內(nèi)置類(lèi)型,但不包括指針類(lèi)型)添加相應(yīng)的方法。
?法總是綁定對(duì)象實(shí)例,并隱式將實(shí)例作為第?實(shí)參 (receiver),方法的語(yǔ)法如下:
func (receiver ReceiverType) funcName (parameters) (results)
- 參數(shù) receiver 可任意命名。如?法中未曾使?,可省略參數(shù)名。
- 參數(shù) receiver 類(lèi)型可以是 T 或 *T?;?lèi)型 T 不能是接?或指針。
- 不支持重載方法,也就是說(shuō),不能定義名字相同但是不同參數(shù)的方法。
2為類(lèi)型添加方法
2.1基礎(chǔ)類(lèi)型作為接收者
type MyInt int//自定義類(lèi)型,給int改名為MyInt
//在函數(shù)定義時(shí),在其名字之前放上一個(gè)變量,即是一個(gè)方法
func (a MyInt) Add(b MyInt) MyInt {//面向?qū)ο?
return a + b
}
//傳統(tǒng)方式的定義
func Add(a, b MyInt) MyInt {//面向過(guò)程
return a + b
}
func main() {
var a MyInt=1 // a := MyInt(1) 等價(jià)
var b MyInt=1
//調(diào)用func (aMyInt) Add(bMyInt)
fmt.Println("a.Add(b)=",a.Add(b))//a.Add(b)=2
//調(diào)用func Add(a,bMyInt)
fmt.Println("Add(a,b)=",Add(a,b))//Add(a,b)=2
}
通過(guò)上面的例子可以看出,面向?qū)ο笾皇菗Q了一種語(yǔ)法形式來(lái)表達(dá)。方法是函數(shù)的語(yǔ)法糖,因?yàn)閞eceiver其實(shí)就是方法所接收的第1個(gè)參數(shù)。
注意:雖然方法的名字一模一樣,但是如果接收者不一樣,那么方法就不一樣。
2.2結(jié)構(gòu)體作為接收者
方法里面可以訪(fǎng)問(wèn)接收者的字段,調(diào)用方法通過(guò)點(diǎn)(. )訪(fǎng)問(wèn),就像struct里面訪(fǎng)問(wèn)字段一樣:
package main
import "fmt"
func main(){
jeff:=user{1,"jeff",18,"上海"}
fmt.Println(jeff.Add(10))
}
// 相當(dāng)于定義user類(lèi)
type user struct {
id int
name string
age int
addr string
}
// 添加Add方法,接收參數(shù)num
func (p user) Add(num int)int{
fmt.Println(p.age)
return p.age+num
}
3值語(yǔ)義和引用語(yǔ)義
package main
import "fmt"
func main() {
//指針作為接收者,引用語(yǔ)義
jeff := Person{"jeff","男",18}//初始化
fmt.Println("函數(shù)調(diào)用前=",jeff)//函數(shù)調(diào)用前= {jeff 男 18}
(&jeff).Add() // 生效,(&jeff)拿到j(luò)eff的地址(指針)
//jeff.Add() // 修改不生效
fmt.Println("函數(shù)調(diào)用后=",jeff)//函數(shù)調(diào)用后= {aaa 女 22}
fmt.Println("==========================")
chary := Person{"chary","女",18}//初始化
//值作為接收者,值語(yǔ)義
fmt.Println("函數(shù)調(diào)用前=",chary)//函數(shù)調(diào)用前= {chary 女 18}
chary.Add2() //不生效
//(&chary).Add()
fmt.Println("函數(shù)調(diào)用后=",chary)//函數(shù)調(diào)用后= {chary 女 18}
}
type Person struct {
name string
sex string
age int
}
//指針作為接收者,引用語(yǔ)義
func (p *Person) Add(){
//給成員賦值
(*p).name = "aaa"
p.sex = "女"
p.age = 22
}
//值作為接收者,值語(yǔ)義
func (p Person) Add2(){
//給成員賦值
p.name = "bbb"
p.sex = "男"
p.age = 22
}
4方法集
類(lèi)型的方法集是指可以被該類(lèi)型的值調(diào)用的所有方法的集合。
用實(shí)例實(shí)例 value 和 pointer 調(diào)用方法(含匿名字段)不受?法集約束,編譯器編總是查找全部方法,并自動(dòng)轉(zhuǎn)換 receiver 實(shí)參。
4.1類(lèi)型 *T 方法集
一個(gè)指向自定義類(lèi)型的值的指針,它的方法集由該類(lèi)型定義的所有方法組成,無(wú)論這些方法接受的是一個(gè)值還是一個(gè)指針。
如果在指針上調(diào)用一個(gè)接受值的方法,Go語(yǔ)言會(huì)聰明地將該指針解引用,并將指針?biāo)傅牡讓又底鳛榉椒ǖ慕邮照摺?/p>
類(lèi)型 *T ?法集包含全部 receiver T + *T ?法:
type Person struct{
name string
sex byte
age int
}
//指針作為接收者,引用語(yǔ)義
func (p *Person) SetInfoPointer(){
(*p).name="yoyo"
p.sex='f'
p.age=22
}
//值作為接收者,值語(yǔ)義
func (p Person) SetInfoValue(){
p.name="xxx"
p.sex='m'
p.age=33
}
func main() {
//p為指針類(lèi)型
var p*Person = &Person{"mike",'m',18}
p.SetInfoPointer() //func (p)SetInfoPointer()
p.SetInfoValue() //func (*p)SetInfoValue()
(*p).SetInfoValue() //func (*p)SetInfoValue()
}
4.2類(lèi)型 T 方法集
一個(gè)自定義類(lèi)型值的方法集則由為該類(lèi)型定義的接收者類(lèi)型為值類(lèi)型的方法組成,但是不包含那些接收者類(lèi)型為指針的方法。
但這種限制通常并不像這里所說(shuō)的那樣,因?yàn)槿绻覀冎挥幸粋€(gè)值,仍然可以調(diào)用一個(gè)接收者為指針類(lèi)型的方法,這可以借助于Go語(yǔ)言傳值的地址能力實(shí)現(xiàn)。
type Person struct{
name string
sex byte
age int
}
//指針作為接收者,引用語(yǔ)義
func (p *Person) SetInfoPointer(){
(*p).name="yoyo"
p.sex='f'
p.age=22
}
//值作為接收者,值語(yǔ)義
func (p Person)SetInfoValue(){
p.name="xxx"
p.sex='m'
p.age=33
}
func main() {
//p為普通值類(lèi)型
var p Person = Person{"mike",'m',18}
(&p).SetInfoPointer() //func(&p)SetInfoPointer()
p.SetInfoPointer() //func(&p)SetInfoPointer()
p.SetInfoValue() //func(p)SetInfoValue()
(&p).SetInfoValue() //func(*&p)SetInfoValue()
}
5匿名字段
5.1方法的繼承
如果匿名字段實(shí)現(xiàn)了一個(gè)方法,那么包含這個(gè)匿名字段的struct也能調(diào)用該方法。
type Person struct {
name string
sex byte
age int
}
//Person定義了方法
func (p *Person) PrintInfo() {
fmt.Printf("%s,%c,%d\n",p.name,p.sex,p.age)
}
type Student struct {
Person//匿名字段,那么Student包含了Person的所有字段
id int
addr string
}
func main() {
p := Person{"mike",'m',18}
p.PrintInfo()
s := Student{Person{"yoyo",'f',20},2,"sz"}
s.PrintInfo()
}
5.2方法的重寫(xiě)
type Person struct {
name string
sex byte
age int
}
//Person定義了方法
func (p *Person) PrintInfo() {
fmt.Printf("Person:%s,%c,%d\n",p.name,p.sex,p.age)
}
type Student struct {
Person//匿名字段,那么Student包含了Person的所有字段
id int
addr string
}
//Student定義了方法
func (s *Student) PrintInfo() {
fmt.Printf("Student:%s,%c,%d\n",s.name,s.sex,s.age)
}
func main() {
p:=Person{"mike",'m',18}
p.PrintInfo() //Person:mike,m,18
s:=Student{Person{"yoyo",'f',20},2,"sz"}
s.PrintInfo() //Student:yoyo,f,20
s.Person.PrintInfo() //Person:yoyo,f,20
}
6方法值和方法表達(dá)式
類(lèi)似于我們可以對(duì)函數(shù)進(jìn)行賦值和傳遞一樣,方法也可以進(jìn)行賦值和傳遞。
根據(jù)調(diào)用者不同,方法分為兩種表現(xiàn)形式:方法值和方法表達(dá)式。兩者都可像普通函數(shù)那樣賦值和傳參,區(qū)別在于方法值綁定實(shí)例,?方法表達(dá)式則須顯式傳參。
6.1方法值
type Person struct{
name string
sex byte
age int
}
func (p *Person) PrintInfoPointer() {
fmt.Printf("%p,%v\n",p,p)
}
func (p Person) PrintInfoValue(){
fmt.Printf("%p,%v\n",&p,p)
}
func main() {
p:=Person{"mike",'m',18}
p.PrintInfoPointer() //0xc0420023e0,&{mike 109 18}
pFunc1:=p.PrintInfoPointer //方法值,隱式傳遞 receiver
pFunc1() //0xc0420023e0,&{mike 109 18}
pFunc2:=p.PrintInfoValue
pFunc2() //0xc042048420,{mike 109 18}
}
6.2方法表達(dá)式
type Person struct {
name string
sex byte
age int
}
func (p *Person) PrintInfoPointer() {
fmt.Printf("%p,%v\n",p,p)
}
func (p Person) PrintInfoValue() {
fmt.Printf("%p,%v\n",&p,p)
}
func main() {
p:=Person{"mike",'m',18}
p.PrintInfoPointer()//0xc0420023e0,&{mike 109 18}
//方法表達(dá)式,須顯式傳參
//func pFunc1 (p *Person))
pFunc1:=(*Person).PrintInfoPointer
pFunc1(&p) //0xc0420023e0,&{mike 109 18}
pFunc2:=Person.PrintInfoValue
pFunc2(p) //0xc042002460,{mike 109 18}
}以上就是go語(yǔ)言方法集以及為類(lèi)型添加方法的示例解析的詳細(xì)內(nèi)容,更多關(guān)于go語(yǔ)言方法集類(lèi)型添加方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用 go 實(shí)現(xiàn)多線(xiàn)程下載器的方法
本篇文章帶領(lǐng)大家學(xué)習(xí)使用go實(shí)現(xiàn)一個(gè)簡(jiǎn)單的多線(xiàn)程下載器,給她家詳細(xì)介紹了多線(xiàn)程下載原理及實(shí)例代碼,感興趣的朋友跟隨小編一起看看吧2021-10-10
go語(yǔ)言?xún)?nèi)存泄漏的常見(jiàn)形式
本文主要介紹了go語(yǔ)言?xún)?nèi)存泄漏的常見(jiàn)形式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04
更換GORM默認(rèn)SQLite驅(qū)動(dòng)出現(xiàn)的問(wèn)題解決分析
這篇文章主要為大家介紹了更換GORM默認(rèn)SQLite驅(qū)動(dòng)出現(xiàn)的問(wèn)題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01

