Re: [問題] Golang型態轉換

看板Programming作者 (function(){})()時間1年前 (2023/02/08 22:47), 1年前編輯推噓3(304)
留言7則, 4人參與, 1年前最新討論串2/2 (看更多)
※ 引述《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
寫完才發現是去年 9 月的文... orz
02/08 22:58, 1F

02/09 01:53, 1年前 , 2F
趕快支援 dependent types 啊,就不用這
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
嬌嗎XD
03/03 10:34, 6F

03/04 00:49, 1年前 , 7F
沒有啊,我只有提作法沒給範例
03/04 00:49, 7F
文章代碼(AID): #1ZuxO62V (Programming)
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 2 之 2 篇):
文章代碼(AID): #1ZuxO62V (Programming)