go 語言type Method Values vs. Method Expressions

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。


go 語言的type 類型方法定義如下:

func (p mytype) funcname(q type) (r,s type) { return 0,0}

本質上這就是一種文法糖,方法調用如下:
instance.method(args) -> (type).func(instance, args)

instance 就是Reciever.左邊的稱為 Method Value,右邊則是 Method Expression,go推薦使用左邊形式。Method Value 是封裝後的狀態物件,總是與特定的對象執行個體關聯在一起 (類似閉包,拐帶私奔),而Method Expression 函數將 Receiver 作為第一個顯式參數,調用時需額外傳遞。二者本質上沒有區別,只是Method Value 看起來更像物件導向的格式,且編譯器會自動進行類型轉換;Method Expression更直觀,更底層,編譯器不會進行最佳化,會按照實際表達意義去執行,更易於理解。

將 Method Value 賦值給變數,Receiver 執行個體立即被複製,這個和go的一貫作風是一樣的。只進行值傳遞,即使是傳遞指標,也是傳遞指標的拷貝,只是拷貝的指標和原指標都指向一個地方,看起來好像是直接操作原資料。

instance.method(args):可以用 value 或 pointer 變數調用所有綁定的任何方法,編譯器會自動進行類型轉換,轉換後的效果和methods的定義語義一致,和調用者的樣式沒有關係。比如原method定義的Receiver是value形的,即使使用pointer 執行個體變數調用該方法,也是value值拷貝;比如原method定義的Receiver是pointer形的,即使使用value 執行個體變數調用該方法,也能改變Receiver執行個體狀態。


package mainimport ("fmt")type Person struct {Age intName string}func (this Person) Getage() int{ return  this.Age}func (this *Person) Setage(i int){ this.Age =  i}func main(){//初始化s1,s2s1:= Person{Age:12, Name: "tata"}s2:= &Person{Age:100, Name: "tt"}fmt.Println("s1=",s1)fmt.Println("s2=",s2)fmt.Println("------------------------")//可以用 value 或 pointer 調用所有綁定的方法,編譯器自動進行類型轉換(按照method Reciever 的類型是value還是pointer進行轉換,和調用者調用表現形式沒有任何關係,調用執行結果按照method的定義語義進行解釋)fmt.Println("s1.Age=",s1.Getage())fmt.Println("s2.Age=",s2.Getage())fmt.Println("s2.Age=",(*s2).Getage())s1.Setage(110)s2.Setage(101)fmt.Println("s1=",s1)fmt.Println("s1=",s2)    (&s1).Setage(220)fmt.Println("s1=",s1)fmt.Println("------------------------")//如下是Method Value形式引用,其等價於Reciever直接調用,規則和直接調用完全一致f := s1.Getages1.Setage(330)fmt.Println("s1=",s1)fmt.Println("s1.copy.Getage()=",f())fmt.Println("s1=",s1)//如下四種方式也是Method Values模式,編譯器進行自動轉換,任何形式都可以調用成功 fmt.Println("------------------------")sw := (&s1).Setagef2 := (&s1).Getagesw(880)fmt.Println("s1=",s1)fmt.Println("s1.copy.Getage()=",f2())fmt.Println("s1=",s1)ss := s1.Setagef3 := s1.Getagess(990)fmt.Println("s1=",s1)fmt.Println("s1.copy.Getage()=",f3())fmt.Println("s1=",s1)se := s2.Setagef4 := s2.Getagese(110)fmt.Println("s2=",s2)fmt.Println("s2.copy.Getage()=",f4())fmt.Println("s2=",s2)se2 := (*s2).Setagef5 := (*s2).Getagese2(220)fmt.Println("s2=",s2)fmt.Println("s2.copy.Getage()=",f5())fmt.Println("s2=",s2)//如下是Method Expressions, methods Reciever是T,可以被T和*T Type調用; methods Reciever是*T,則只能被*T Type調用;調用第一個參數類型要和調用者一致:T對應T類型變數,*T對用*T類型變數// T.Method.(var T)// (*T).Method.(var * T)fmt.Println("------------------------")m := Person.Getage(s1)//m5 := Person.Getage(&s1) 報錯,前後類型不一致//m6 := Person.Getage(s2) 報錯,前後類型不一致m2 := (*Person).Getage(&s1)n := (*Person).Getage(s2)n2 := Person.Getage(*s2)fmt.Println("m=",m)fmt.Println("m2=",m2)fmt.Println("n2=",n)fmt.Println("n2=",n2)fmt.Println("------------------------")//Person.Setage(s1,9999)不允許, *T類型方法,T不能調用//Person.Setage(&s1,9999)也是不允許,*T類型方法,T不能調用(*Person).Setage(s2,500)fmt.Println("s2=",s2)//(*Person).Setage(s1,1000) 不允許 ,前後類型不一致//Person.Setage(s2,1000) 不允許(*Person).Setage(&s1,1000)fmt.Println("s1=",s1) }




聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.