Re: [問題] Golang型態轉換
※ 引述《umaka0325 (Umaka)》之銘言:
: 最近在摸索Go的相關語法碰到一些問題想請教一下
: 程式碼如下:
: type Person struct {
: Name string
: Age int
: }
: func test1(p *Person) {
: p.Name = "123"
: }
: func test(p any) {
: test1(p.(*Person))
: ^^^^^^^^
: }
: 想請問底線部分的*Person這個結構有什麼辦法從輸入p any動態產生嗎?
: 謝謝!!
初學者常常希望能存取不特定型別的共同欄位
不過... https://tenor.com/bhDEJ.gif
正常的寫法都是改寫成 interface
type Person interface {
GetName() string
GetAge() int
}
type person struct {
Name string
Age int
}
func (p *person) GetName() string {
return p.Name
}
func (p *person) GetAge() int {
return p.Age
}
func test(p Person) {
otherfunc(p.GetName(), ...)
otherfunc(p.GetAge(), ...)
}
func callTest() {
pe := &person{
Name: "John Doe",
Age: 20,
}
test(pe)
}
對,golang 的 interface 就是如此繁瑣
--
如果共通 type 只有幾種 struct 會用到
可以獨立出一個 base struct embed 進其他 struct
type Model struct {
ID string
}
type RecordA struct {
Model
Entry1 int
}
type RecordB struct {
Model
Entry2 int
}
func test(record *Model) {
otherfunc(record.ID, ...)
}
func callTest() {
a := &RecordA{
Model: Model{
ID: "hello",
},
Entry1: 0,
}
b := &RecordB{
Model: Model{
ID: "world",
},
Entry2: 1,
}
test(a.Model)
test(b.Model)
}
但是這種寫法是比較不推薦的。
原因是易遭到濫用,很多人會把這種語法當作繼承 (inheritance) 使用,
但 golang 沒有繼承,只有組合 (composition),所以他還是分開的兩種 type。
當你的 type 會跨出這個 package 的時候建議避免採用這種方式。
當然,如果你知道自己在做什麼也不是不能用。
比較經典的範例是 gorm.Model
https://gorm.io/docs/models.html
或是常常會有人把 sync.Mutex 嵌進 struct 裡。
初學者看完 Effective Go 建議可以參考
https://github.com/uber-go/guide/blob/master/style.md
當然這不代表所有業界程式碼風格規範,
但這份文件好處是為什麼要這樣做的理由都告訴你了。
裡面有提到 Avoid Embedding Types in Public Structs,
給的理由是 These embedded types leak implementation details,
inhibit type evolution, and obscure documentation.
簡單的說就是 exported fields & struct methods 會被一併公開,
以及修改被嵌入的 struct 會影響所有有嵌入它的 struct,
造成可能的同名 field 及 method 衝突,製造修改衍生 struct 的困擾。
--
那如果因為一些技術限制不能改寫 interface 也不能用 embed struct 呢?
最後的大招是用 reflect,寫起來太醜我不想寫,
如果寫到要用 reflect 那你有 99% 的可能寫錯了。
這邊還是稍微提一下作法。
用 reflect 你可以判斷傳進來的是 slice, array, struct,
接著可以再去讀它有的 field name,進而去存取該 field 的值。
為什麼這個寫法常常是錯的呢?因為它效能不太好。
在上述兩種方法前,reflect 常常會是最終不得已採用的解法。
一般常見用到 reflect 的寫法有... gorm... 又是你...
https://github.com/go-gorm/gorm/blob/v1.24.5/schema/schema.go#L79
因為 gorm 幾乎所有操作都是用 interface{} 去接,
所以它只能長成 reflect 的那種樣子。
可以的話用 interface, type assertion 去做,不要用 reflect。
除了效能會受影響外,它還很難讀。
除此之外,還有些 assetion/mock libraries 會用到 reflect。
但那也是無可厚非,因為它不知道使用者會傳什麼 type 進來,
也沒辦法用 interface 定義,不然為了寫測試真的要萬物 interface 了。
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 219.91.34.68 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/Programming/M.1675867654.A.09F.html
※ 編輯: s25g5d4 (219.91.34.68 臺灣), 02/08/2023 22:51:15
※ 編輯: s25g5d4 (219.91.34.68 臺灣), 02/08/2023 22:54:21
→
02/08 22:58,
1年前
, 1F
02/08 22:58, 1F
推
02/09 01:53,
1年前
, 2F
02/09 01:53, 2F
→
02/09 01:53,
1年前
, 3F
02/09 01:53, 3F
推
02/21 11:08,
1年前
, 4F
02/21 11:08, 4F
推
03/03 10:34,
1年前
, 5F
03/03 10:34, 5F
→
03/03 10:34,
1年前
, 6F
03/03 10:34, 6F
→
03/04 00:49,
1年前
, 7F
03/04 00:49, 7F
討論串 (同標題文章)
Programming 近期熱門文章
PTT數位生活區 即時熱門文章