go語(yǔ)言方法集為類型添加方法示例解析
1概述
在面向?qū)ο缶幊讨校粋€(gè)對(duì)象其實(shí)也就是一個(gè)簡(jiǎn)單的值或者一個(gè)變量,在這個(gè)對(duì)象中會(huì)包含一些函數(shù),這種帶有接收者的函數(shù),我們稱為方法(method)。本質(zhì)上,一個(gè)方法則是一個(gè)和特殊類型關(guān)聯(lián)的函數(shù)。
一個(gè)面向?qū)ο蟮某绦驎?huì)用方法來表達(dá)其屬性和對(duì)應(yīng)的操作,這樣使用這個(gè)對(duì)象的用戶就不需要直接去操作對(duì)象,而是借助方法來做這些事情。
在Go語(yǔ)言中,可以給任意自定義類型(包括內(nèi)置類型,但不包括指針類型)添加相應(yīng)的方法。
?法總是綁定對(duì)象實(shí)例,并隱式將實(shí)例作為第?實(shí)參 (receiver),方法的語(yǔ)法如下:
func (receiver ReceiverType) funcName (parameters) (results)
- 參數(shù) receiver 可任意命名。如?法中未曾使?,可省略參數(shù)名。
- 參數(shù) receiver 類型可以是 T 或 *T?;愋?T 不能是接?或指針。
- 不支持重載方法,也就是說,不能定義名字相同但是不同參數(shù)的方法。
2為類型添加方法
2.1基礎(chǔ)類型作為接收者
type MyInt int//自定義類型,給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 {//面向過程 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 }
通過上面的例子可以看出,面向?qū)ο笾皇菗Q了一種語(yǔ)法形式來表達(dá)。方法是函數(shù)的語(yǔ)法糖,因?yàn)閞eceiver其實(shí)就是方法所接收的第1個(gè)參數(shù)。
注意:雖然方法的名字一模一樣,但是如果接收者不一樣,那么方法就不一樣。
2.2結(jié)構(gòu)體作為接收者
方法里面可以訪問接收者的字段,調(diào)用方法通過點(diǎn)(. )訪問,就像struct里面訪問字段一樣:
package main import "fmt" func main(){ jeff:=user{1,"jeff",18,"上海"} fmt.Println(jeff.Add(10)) } // 相當(dāng)于定義user類 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方法集
類型的方法集是指可以被該類型的值調(diào)用的所有方法的集合。
用實(shí)例實(shí)例 value 和 pointer 調(diào)用方法(含匿名字段)不受?法集約束,編譯器編總是查找全部方法,并自動(dòng)轉(zhuǎn)換 receiver 實(shí)參。
4.1類型 *T 方法集
一個(gè)指向自定義類型的值的指針,它的方法集由該類型定義的所有方法組成,無論這些方法接受的是一個(gè)值還是一個(gè)指針。
如果在指針上調(diào)用一個(gè)接受值的方法,Go語(yǔ)言會(huì)聰明地將該指針解引用,并將指針?biāo)傅牡讓又底鳛榉椒ǖ慕邮照摺?/p>
類型 *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為指針類型 var p*Person = &Person{"mike",'m',18} p.SetInfoPointer() //func (p)SetInfoPointer() p.SetInfoValue() //func (*p)SetInfoValue() (*p).SetInfoValue() //func (*p)SetInfoValue() }
4.2類型 T 方法集
一個(gè)自定義類型值的方法集則由為該類型定義的接收者類型為值類型的方法組成,但是不包含那些接收者類型為指針的方法。
但這種限制通常并不像這里所說的那樣,因?yàn)槿绻覀冎挥幸粋€(gè)值,仍然可以調(diào)用一個(gè)接收者為指針類型的方法,這可以借助于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為普通值類型 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方法的重寫
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á)式
類似于我們可以對(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ǔ)言方法集以及為類型添加方法的示例解析的詳細(xì)內(nèi)容,更多關(guān)于go語(yǔ)言方法集類型添加方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go語(yǔ)言每天必學(xué)之switch語(yǔ)句
這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言每天必學(xué)之switch語(yǔ)句的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12go語(yǔ)言代碼生成器code?generator使用示例介紹
這篇文章主要為大家介紹了go語(yǔ)言代碼生成器code?generator的使用簡(jiǎn)單介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05golang如何實(shí)現(xiàn)三元運(yùn)算符功能
這篇文章主要介紹了在其他一些編程語(yǔ)言中,如?C?語(yǔ)言,三元運(yùn)算符是一種可以用一行代碼實(shí)現(xiàn)條件選擇的簡(jiǎn)便方法,那么在Go語(yǔ)言中如何實(shí)現(xiàn)類似功能呢,下面就跟隨小編一起學(xué)習(xí)一下吧2024-02-02Golang設(shè)計(jì)模式之外觀模式的實(shí)現(xiàn)
這篇文章主要介紹了Golang設(shè)計(jì)模式之外觀模式的實(shí)現(xiàn),外觀模式是一種常用的設(shè)計(jì)模式之一,是一種結(jié)構(gòu)型設(shè)計(jì)模式,它提供了一個(gè)簡(jiǎn)單的接口來訪問復(fù)雜系統(tǒng)的各種功能,從而降低了系統(tǒng)的復(fù)雜度,需要詳細(xì)了解可以參考下文2023-05-05Go語(yǔ)言WaitGroup使用時(shí)需要注意的坑
Go語(yǔ)言中WaitGroup的用途是它能夠一直等到所有的goroutine執(zhí)行完成,并且阻塞主線程的執(zhí)行,直到所有的goroutine執(zhí)行完成。之前一直使用也沒有問題,但最近通過同事的一段代碼引起了關(guān)于WaitGroup的注意,下面這篇文章就介紹了WaitGroup使用時(shí)需要注意的坑及填坑。2016-12-12