goLang 之 type Method Value 和Method Expressions

在使用 goLang時,常常遇到 Method ValueMethod Expressions的問題,簡單記錄一下二者的使用區別

goLangtype類型方法定義以下:express

func (p myType) funcName(q type) (r,s type){return 0,0) //相似這樣

本質上這就是一種語法糖,方法調用以下:函數

instance.method(args) ---> (type).func(instance,args)

instance就是Receiver. 左邊的稱爲Method value.右邊的則是Method Expression.其實goLang 是推薦使用左邊形式的,由於比較好理解。Method Value是包裝後的狀態對象,老是與特定的對象實例關聯在一塊兒,而Method Expression函數將Receiver做爲第一個顯示參數,調用時需手動傳遞。兩者本質沒有什麼區別優化

只是Method value看起來更像面向對象的格式,且編譯器會自動進行類型轉換。 Method Expression更直觀,更底層,編譯器不會進行優化,會按照實際表達意義去執行。this

Method Value賦值給變量,Receiver實例當即被複制,這個和goLang的一向做風是同樣的。只進行值傳遞,即便是傳遞指針,也只是傳遞指針的拷貝,只是拷貝的指針和原指針都指向一個地方,看起來好像是直接操做原數據.net

instance.method(args):能夠用 value(值)pointer(指針) 變量調用全部綁定的任何方法,編譯器會自動進行類型轉換,轉換後的效果和method的定義語義一致,和調用者的樣式沒有關係。指針

method定義的 Receivervalue形的,即便使用 pointer實例變量調用該方法,也是 value值拷貝;

method定義的Receiverpointer形的,即便使用value 實例變量調用該方法,也能改變Receiver實例狀態。code

package main  
  
import (  
        "fmt"  
)  
  
  
type Person struct {  
        Age int  
        Name string  
}  
  
  
func (this Person) Getage() int{  
    return  this.Age      
}  
  
func (this *Person) Setage(i int){  
    this.Age =  i  
}  
  
func main(){  
        //初始化s1,s2  
        s1:= 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.Getage  
        s1.Setage(330)  
        fmt.Println("s1=",s1)  
        fmt.Println("s1.copy.Getage()=",f())  
        fmt.Println("s1=",s1)  
  
//以下四種方式也是Method Values模式,編譯器進行自動轉換,任何形式均可以調用成功   
        fmt.Println("------------------------")  
        sw := (&s1).Setage  
        f2 := (&s1).Getage  
        sw(880)  
        fmt.Println("s1=",s1)  
        fmt.Println("s1.copy.Getage()=",f2())  
        fmt.Println("s1=",s1)  
  
        ss := s1.Setage  
        f3 := s1.Getage  
        ss(990)  
        fmt.Println("s1=",s1)  
        fmt.Println("s1.copy.Getage()=",f3())  
        fmt.Println("s1=",s1)  
  
        se := s2.Setage  
        f4 := s2.Getage  
        se(110)  
        fmt.Println("s2=",s2)  
        fmt.Println("s2.copy.Getage()=",f4())  
        fmt.Println("s2=",s2)  
  
        se2 := (*s2).Setage  
        f5 := (*s2).Getage  
        se2(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)  
 }

其實有過面向對象經驗,對於method value會比較容易理解,能夠很是靈活使用。而對於method expression,重點理解以下一段話就能夠:對象

methods ReceiverT,能夠被 T*T Type調用;
methods Receiver*T,則只能被 *T Type調用;

調用的時候第一個參數類型要和調用者一致:T對應T類型變量,*T對用*T類型變量blog

參考:http://blog.csdn.net/hittata/...ci

相關文章
相關標籤/搜索