亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

去接收器方法調用語法混亂

去接收器方法調用語法混亂

Go
大話西游666 2021-05-21 18:18:51
我只是在閱讀“有效執行”并在“指針與值”部分中接近結尾處說:關于接收方的指針與值的規則是,可以在指針和值上調用值方法,但是只能在指針上調用指針方法。這是因為指針方法可以修改接收者。在值的副本上調用它們將導致那些修改被丟棄。為了測試它,我這樣寫:package mainimport (  "fmt"  "reflect")type age intfunc (a age) String() string {  return fmt.Sprintf("%d yeasr(s) old", int(a))}func (a *age) Set(newAge int) {  if newAge >= 0 {    *a = age(newAge)  }}func main() {  var vAge age = 5  pAge := new(age)  fmt.Printf("TypeOf =>\n\tvAge: %v\n\tpAge: %v\n", reflect.TypeOf(vAge),    reflect.TypeOf(pAge))  fmt.Printf("vAge.String(): %v\n", vAge.String())  fmt.Printf("vAge.Set(10)\n")  vAge.Set(10)  fmt.Printf("vAge.String(): %v\n", vAge.String())  fmt.Printf("pAge.String(): %v\n", pAge.String())  fmt.Printf("pAge.Set(10)\n")  pAge.Set(10)  fmt.Printf("pAge.String(): %v\n", pAge.String())}即使文檔說它不應該編譯,它也可以編譯,因為Set()不應通過值var調用指針方法vAge。我在這里做錯什么了嗎?
查看完整描述

2 回答

?
白衣染霜花

TA貢獻1796條經驗 獲得超10個贊

這是有效的,因為它vAge是可尋址的。請參閱語言規范下的“通話”中的最后一段:

如果x的方法集包含m并且參數列表可以分配給m的參數列表,則方法調用xm()是有效的。如果x是可尋址的并且&x的方法集包含m,則xm()是(&x).m()的簡寫。


查看完整回答
反對 回復 2021-05-24
?
揚帆大魚

TA貢獻1799條經驗 獲得超9個贊

vAge不被視為僅是“值變量”,因為它是內存中存儲type值的已知位置age??v觀vAge只能作為它的價值,vAge.Set(10)不是因為對自己的表現有效的,但由于vAge是可尋址的,該規范宣稱它的好來治療表達簡寫為“獲得vAge的地址,并調用設置該”編譯-time時,我們將能夠驗證這Set是為age或方法設置的一部分*age。您基本上允許編譯器在確定必要和可能的情況下對原始表達式進行文本擴展。

同時,編譯器將允許您調用,age(23).String()但不允許age(23).Set(10)。在這種情況下,我們正在使用type的不可尋址值age。由于說的無效&age(23),所以說的無效(&age(23)).Set(10); 編譯器不會進行該擴展。

查看Effective Go示例,您并沒有直接調用b.Write()我們知道b的完整類型的范圍。相反,您是制作的臨時副本,b并嘗試將其作為type的值傳遞出去interface io.Writer()。問題在于,實現Printf不會對傳入的對象一無所知,只是它承諾會知道如何接收Write(),因此它不知道在調用函數之前將abyteSlice轉換為a即可*ByteSlice。是否尋址的決定b必須在編譯時進行,PrintF其前提是其第一個參數知道如何在Write()不被引用的情況下進行接收。

您可能會認為,如果系統知道如何獲取age指針并將其轉換為age值,那么它應該可以執行相反的操作;但是,實際上并沒有意義。在Effective Go示例中,如果要傳遞b而不是&b,則將修改一個在PrintF返回后將不再存在的切片,這幾乎沒有用。在age上面的示例中,采用值23并用value覆蓋它實際上沒有任何意義10。在第一種情況下,讓編譯器停止并詢問程序員在移交時真正意味著什么是有意義的b。在后一種情況下,對于編譯器而言,拒絕修改常量值當然是有意義的。

此外,我不認為系統正在動態地將age的方法設置擴展為*age;。我的瘋狂猜測是,為每種基本類型的方法靜態地賦予了指針類型一個方法,該方法只是取消引用指針并調用該基本方法。自動執行此操作很安全,因為按值接收方法中的任何內容都無法更改指針。在另一個方向上,通過包裝被要求修改數據的方法來擴展一組要求修改數據的方法并不總是很有意義,因為它們所修改的數據此后不久就會消失。在某些情況下,這樣做確實是有意義的,但是這需要程序員明確地決定,并且編譯器停止并要求這樣做是有意義的。

tl; dr我認為,Effective Go中的段落可能需要重新措辭(盡管我可能太long了以至于無法勝任),但這是正確的。類型的指針*X實際上可以訪問的所有X方法,但“ X”不能訪問*X的。因此,當確定一個對象是否可以滿足給定的接口時,*X被允許滿足X可以實現的任何接口,但是反之則不成立。此外,即使X已知作用域中的類型變量在編譯時是可尋址的,所以編譯器可以將其轉換為*X-它會出于接口實現的目的而拒絕這樣做,因為這樣做可能沒有意義。 。


查看完整回答
反對 回復 2021-05-24
  • 2 回答
  • 0 關注
  • 258 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號