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

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

如何在 Unmarshal 中使用泛型 (go 1.18)

如何在 Unmarshal 中使用泛型 (go 1.18)

Go
喵喔喔 2022-12-05 16:38:05
我是 golang 泛型的新手,具有以下設置。我收集了大量不同類型的報告。每個報告都有封閉的字段所以我把它包裹在一個ReportContainerImpl我使用了一個類型參數, [T Reportable]其中Reportable定義如下type Reportable interface {    ExportDataPointReport | ImportDataPointReport | MissingDataPointReport | SensorThresoldReport}類型約束中的每個類型都是要嵌入到容器中的結構。type ReportContainerImpl[T Reportable] struct {    LocationID string `json:"lid"`    Provider string `json:"pn"`    ReportType ReportType `json:"m"`    Body T `json:"body"`}我使用鑒別ReportType器來確定具體類型 when Unmarshal。type ReportType stringconst (    ReportTypeExportDataPointReport ReportType = "ExportDataPointReport"    ReportTypeImportDataPointReport ReportType = "ImportDataPointReport"    ReportTypeMissingDataPointReport ReportType = "MissingDataPointReport"    ReportTypeSensorThresoldReport ReportType = "SensorThresoldReport")由于go不支持struct的類型斷言(僅接口),因此無法在Unmarshal. go也不支持指向“原始”泛型類型的指針。因此,我創建了一個實現的接口ReportContainerImpl。type ReportContainer interface {    GetLocationID() string    GetProvider() string    GetReportType() ReportType    GetBody() interface{}}然后我得到的問題是我不能以任何形式或形狀對返回類型進行類型約束,并且回到函數的“自由文本語義”以GetBody()允許在完成時進行類型斷言Unmarshal。    container, err := UnmarshalReportContainer(data)    if rep, ok := container.GetBody().(ExportDataPointReport); ok {      // Use the ReportContainerImpl[ExportDataPointReport] here...    }也許我弄錯了?- 但無論我這樣做,我總是在某個地方結束之前需要一個interface{}或知道確切的類型Unmarshal你有更好的建議如何以一種類型(更安全)的方式解決這個問題嗎?干杯,馬里奧 :)為了完整起見,我在UnmarshalReportContainer這里添加func UnmarshalReportContainer(data []byte) (ReportContainer, error) {    type Temp struct {        LocationID string `json:"lid"`        Provider string `json:"pn"`        ReportType ReportType `json:"m"`        Body *json.RawMessage `json:"body"`    }    var temp Temp    err := json.Unmarshal(data, &temp)    if err != nil {        return nil, err    }
查看完整描述

1 回答

?
鳳凰求蠱

TA貢獻1825條經驗 獲得超4個贊

但是無論我這樣做,我總是在某處需要一個接口{}或在 Unmarshal 之前知道確切的類型


恰恰。


在編寫代碼時,實例化某些泛型類型或函數所需的具體類型ReportContainerImpl必須UnmarshalReportContainer在編譯時知道。當您用實際數據填充字節片時,JSON 解組發生在運行時。


要根據某些區分值解組動態 JSON,您仍然需要一個switch.


你有更好的建議如何以一種類型(更安全)的方式解決這個問題嗎?


只是放棄參數多態性。這里不太合適。保留您現在擁有的代碼json.RawMessage,在 中有條件地解組動態數據,switch并返回實現ReportContainer接口的具體結構。


作為通用解決方案——當且僅當您可以克服這個先有雞還是先有蛋的問題并在編譯時使類型參數已知時,您可以編寫一個最小的通用解組函數,如下所示:


func unmarshalAny[T any](bytes []byte) (*T, error) {

    out := new(T)

    if err := json.Unmarshal(bytes, out); err != nil {

        return nil, err

    }

    return out, nil

}

這只是為了說明原理。請注意,它json.Unmarshal已經接受任何類型,因此如果您的泛型函數實際上除了返回并沒有執行任何操作new(T),就像在我的示例中一樣,它與“內聯”整個事物沒有什么不同,就好像它unmarshalAny不存在一樣。


v, err := unmarshalAny[SomeType](src)

功能上等同于


out := &SomeType{}

err := json.Unmarshal(bytes, out)

如果您打算在 中放入更多邏輯unmarshalAny,則可能需要使用它。你的旅費可能會改變; 通常,在實際上不需要時不要使用類型參數。


查看完整回答
反對 回復 2022-12-05
  • 1 回答
  • 0 關注
  • 470 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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