關於golang interface中T和*T的一個小測試和思考
阿新 • • 發佈:2022-04-21
首先
貼一下參考的部落格資料。
https://www.cnblogs.com/shijingxiang/articles/12201984.html
背景:
golang中使用interface實現類似於C++或者JAVA 的多型,其中比較複雜的是介面中函式呼叫者引數可能為T或者*T。
按照官方文件說明,interface中 T 型別只能處理接收者引數為 T, T型別可以呼叫接收者引數為T或者T。
結論:
interface呼叫 *T型別呼叫接收者引數為T的函式時候,做法應該是對 *T型別變數做一個 反操作 類似於下面
package main import ( "fmt" ) type Submit interface { work() } type Student struct { Name string } func (s Student) work() { fmt.Printf("work: %p\n", &s) s.Name += "s" } func doWork(sub Submit) { sub.work() sub.work() } func main() { stu := &Student{Name: "wyh"} fmt.Printf("main: %p\n", stu) // 此處傳遞為Student指標,work函式為Student型別 fmt.Println(stu) doWork(stu) fmt.Println(stu) }
結果為
main: 0xc000048230
&{wyh}
work: 0xc000048260
work: 0xc000048270
&{wyh}
可以看到兩次work函式的Student不是同個地址
在以上程式碼中`sub.work()`函式被呼叫的時候,我理解編譯器做的事情為
var temp Student
temp = *(sub.(&Student)).DeepCopy()
temp.work()
可以多做一個嘗試,當work函式為接收者引數為*Student的時候,work函式每一次呼叫的s打印出來地址都是一致
思考
- 為什麼T型別只能呼叫接收者引數為T,而不能是*T,反之*T可以呼叫T和*T。
兩個問題,後一個*T可以呼叫T和*T,原理就是上面猜測。
T型別呼叫*T會發生什麼可能,首先我覺得技術是可以做到,相當於對一個物件定址應該是沒啥問題
但為什麼Golang不支援的原因是可能定址過後,會有人手賤把它指向另一個其他物件A,假設A又不符合interface定義,會發生內部邏輯錯誤
這點的推測是從第一種情況中得出,為什麼*T呼叫T的時候,是每次都例項化一個新的物件,
不就是為了安全,而且保持一種約定,*T才能修改物件內容,T不能修改內容。