第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

如何匹配字符串golang struct標(biāo)簽

如何匹配字符串golang struct標(biāo)簽

Go
UYOU 2022-11-23 14:00:59
我有一個(gè)帶有動(dòng)態(tài)鍵的 json 數(shù)據(jù),例如:{  "id_employee": 123}或者{  "id_user": 321}我正在嘗試將數(shù)據(jù)解組為結(jié)構(gòu)。在解組數(shù)據(jù)后,如何創(chuàng)建結(jié)構(gòu)標(biāo)簽以匹配示例中的所有這兩個(gè)鍵“id_user”和“id_employee”?interface User struct {   Id int64 .....}
查看完整描述

1 回答

?
holdtom

TA貢獻(xiàn)1805條經(jīng)驗(yàn) 獲得超10個(gè)贊

在我們開(kāi)始之前

一個(gè)小的免責(zé)聲明:我在腦海中寫(xiě)下了下面的所有代碼片段,沒(méi)有校對(duì)或任何類似的東西。該代碼尚未準(zhǔn)備好復(fù)制粘貼。這個(gè)答案的重點(diǎn)是為您提供一些方法,讓您可以按照您的要求進(jìn)行操作,解釋為什么選擇給定選項(xiàng)可能是個(gè)好主意,等等……第三種方法絕對(duì)是更好的方法,但鑒于信息有限(沒(méi)有具體 WRT 您要解決的問(wèn)題),您可能需要做更多的挖掘才能獲得最終解決方案。


接下來(lái),我必須問(wèn)你為什么要嘗試做這樣的事情。如果您想要一種可用于解組不同有效負(fù)載的單一類型,我認(rèn)為您會(huì)引入很多代碼味道。如果有效負(fù)載不同,則它們必須代表不同的數(shù)據(jù)。想要對(duì)多個(gè)數(shù)據(jù)集使用單一的包羅萬(wàn)象的類型 IMO 只是在自找麻煩。我將提供幾種方法,但我想在開(kāi)始之前非常清楚這一點(diǎn):


盡管這是可能的,但這是個(gè)壞主意

一個(gè)較小的問(wèn)題,但我必須指出:您包括這樣的示例類型:


interface User struct {

    Id int64

}

這是完全錯(cuò)誤的。具有字段的結(jié)構(gòu)不是接口,因此我將假設(shè)兩件事向前發(fā)展。一種是您需要專用的用戶類型,例如:


type Employee struct {

    Id int64

}

type Employer struct {

    Id int64

}

和一個(gè):


type User interface {

   ID() int64

}

解組這些東西

因此,您可以通過(guò)多種方式完成您想要做的事情。凌亂但簡(jiǎn)單的方法是擁有一個(gè)包含字段所有可能排列的單一類型:


type AllUser struct {

    UID int64 `json:"user_id"`

    EID int64 `json:"employee_id"`

}

這可確保user_id employee_id您的 JSON 輸入中的兩個(gè)字段都能找到歸宿,并填充 ID 字段。但是,當(dāng)您想要實(shí)現(xiàn)User接口時(shí),真正的混亂很快就會(huì)變得明顯:


func (a AllUser) ID() int64 {

    if a.UID != 0 {

        return a.UID

    }

    if a.EID != 0 {

        return a.EID

    }

    // and so on

    return 0 // probably an error?

}

對(duì)于 getter 來(lái)說(shuō),這只是很多樣板代碼,但是 setter 呢?該字段可能尚未設(shè)置。您需要找出一種方法來(lái)從單個(gè)設(shè)置器中設(shè)置正確的 ID 字段。傳入一個(gè)枚舉/常量來(lái)指定您要設(shè)置的字段,乍一看似乎是一種合理的方法,但仔細(xì)想想:它首先違背了擁有接口的目的。你會(huì)失去所有的抽象。所以這種做法是相當(dāng)有缺陷的。


此外,如果您設(shè)置了員工 ID,則其他 ID 字段將默認(rèn)為它們的 nil 值(0 表示 int64)。再次編組類型將導(dǎo)致 JSON 輸出如下:


{

    "employee_id": 123,

    "user_id": 0,

    "employer_id": 0,

}

您可以通過(guò)將類型更改為使用指針來(lái)解決此問(wèn)題,并添加omitempty以跳過(guò)nilJSON 輸出中的字段:


type AllUser struct {

    EID *int64 `json:"employee_id,omitempty"`

    UID *int64 `json:"user_id,omitempty"`

}

同樣,這是一件令人討厭的事情,將導(dǎo)致您不得不在整個(gè)代碼中處理指針字段(在不同的時(shí)間點(diǎn)可能為 nil,也可能不為 nil)。這并不難做到,但它增加了很多噪音,使代碼更容易出現(xiàn)錯(cuò)誤,并且是一個(gè)全面的 PITA,你應(yīng)該盡可能避免。你可以很容易地避免它。


自定義編組

更好的方法是創(chuàng)建一個(gè)嵌入數(shù)據(jù)特定類型的基類型。假設(shè)我們已經(jīng)創(chuàng)建了我們的Employeeand EmployerorCustomer類型。這些類型都有一個(gè)ID字段,帶有自己的標(biāo)簽,如下所示:


type Employee struct {

    ID int64 `json:"employee_id"`

}


type FooUser struct {

    ID int64 `json:"foo_id"`

}

接下來(lái)要做的是創(chuàng)建一個(gè)嵌入所有特定用戶類型的半通用類型。name可以在此基本類型上添加共享字段(例如,如果所有數(shù)據(jù)集都有一個(gè)字段)。接下來(lái)您要做的是將此復(fù)合類型嵌入到另一種實(shí)現(xiàn)自定義編組/解組的類型中。這將允許您設(shè)置一些字段(就像我在此處的示例中包含的:例如,指定您正在處理的用戶類型的字段)。


type UserType int


const (

    EmployeeUserType UserType = iota

    FooUserType

    // go-style enum values for all user-types

)


type BaseUser struct {

    WrappedUser

}


type WrappedUser struct {

    *Employee // embed pointers to these types

    *FooUser

    Name       string   `json:"name"`

    Type       UserType `json:"-"` // ignore this in JSON unmarshalling

}


func (b *BaseUser) UnmarshalJSON(data []byte) error {

    if err := json.Unmarshal(data, &b.WrappedUser); err != nil {

        return err

    }

    if b.Employee != nil {

        b.Type = EmployeeUserType // set the user-type flag

    }

    if b.FooUser != nil {

        b.Type = FooUserType

    }

    return nil

}


func (b BaseUser) MarshalJSON() ([]byte, error) {

    return json.Marshal(b.WrappedUser) // wrapped user doesn't have any custom handling

}

現(xiàn)在要實(shí)現(xiàn)User接口,你可以在WrappedUser類型上實(shí)現(xiàn)它(BaseUser嵌入它,所以方法可以通過(guò)任何一種方式訪問(wèn)),你現(xiàn)在準(zhǔn)確地知道你需要獲取/設(shè)置哪些字段,因?yàn)槟阌蓄愋蜆?biāo)志來(lái)告訴你:


func (w WrappedUser) ID() int64 {

    switch w.Type {

    case EmployeeUserType:

        return w.Employee.ID

    case FooUserType:

        return w.FooUser.ID

    }

    return 0

}

setter 也可以這樣做:


func (w *WrappedUser) SetID(id int64) {

    switch w.Type {

    case EmployeeUserType:

        if w.Employee == nil {

            w.Employee = &Employee{}

        }

        w.Employee.ID = id

    case FooUserType:

        if w.FooUser == nil {

            w.FooUser = &FooUser{}

        }

        w.FooUser.ID = id

    }

}

使用像這樣的自定義編組和嵌入類型稍微好一些,但正如您可能通過(guò)查看這個(gè)非常簡(jiǎn)單的示例可以看出的那樣,處理/維護(hù)它很快就會(huì)變得非常麻煩。


翻轉(zhuǎn)腳本

現(xiàn)在我假設(shè)您希望能夠?qū)⒉煌挠行ж?fù)載解組為單一類型,因?yàn)楹芏嘧侄问枪蚕淼?,但?ID 字段之類的東西可能不同(user_id與employee_id本例相比)。這是完全正常的。您在問(wèn)如何使用單一的包羅萬(wàn)象的類型。這是一個(gè) XY 問(wèn)題。與其詢問(wèn)如何為所有特定數(shù)據(jù)集使用單一類型,不如簡(jiǎn)單地為共享字段創(chuàng)建一個(gè)類型,然后依次將其包含到特定類型中?它與自定義編組的方法非常相似,但要簡(jiǎn)單大約 1,000,000 倍:


// BaseUser contains all fields all specific user-types share

type BaseUser struct {

    Name   string `json:"name"`

    Active bool   `json:"active"`

    // etc...

}


// Employee is a user, that happens to be an employee

type Employee struct {

    ID int64 `json:"employee_id"`

    BaseUser // embed the other fields that all users share here

}


type FooUser struct {

    ID int64 `json:"foo_id"`

    BaseUser

    Name string `json:"foo_user"` // override the name field of BaseUser

}

User在類型上實(shí)現(xiàn)接口的所有方法BaseUser,只在特定類型上實(shí)現(xiàn)ID getter/setter,就大功告成了。如果您需要覆蓋一個(gè)字段,就像我Name在FooUser類型上所做的那樣,那么您只需覆蓋該單一類型上該字段的 getter/setter:


func (f FooUser) Name() string {

    return f.Name

}

func (f *FooUser) SetName(n string) {

    f.Name = n

}

這就是您需要做的全部。好,易于。您正在使用 JSON 數(shù)據(jù)。這意味著您正在從某個(gè)地方獲取該數(shù)據(jù)(API,或者作為對(duì)某種數(shù)據(jù)存儲(chǔ)的查詢的響應(yīng))。如果您正在處理您請(qǐng)求的數(shù)據(jù),您至少應(yīng)該知道您期望什么樣的響應(yīng)數(shù)據(jù)。API 是契約:我調(diào)用 X,服務(wù)響應(yīng)我以給定格式請(qǐng)求的數(shù)據(jù)或錯(cuò)誤。我從商店查詢數(shù)據(jù)集 Y,要么得到請(qǐng)求的數(shù)據(jù),要么什么也得不到(可能會(huì)出錯(cuò))。


如果您從文件或某些服務(wù)中提取數(shù)據(jù),并且無(wú)法預(yù)測(cè)返回的內(nèi)容,則需要修復(fù)數(shù)據(jù)源。您不應(yīng)該嘗試圍繞更基本的問(wèn)題進(jìn)行編碼。必須,我會(huì)花一些時(shí)間編寫(xiě)一個(gè)小程序,例如,讀取源文件,將其解組為像map[string]interface{}. ,按類型分組,因此我可以以更理智的方式攝取數(shù)據(jù)。


查看完整回答
反對(duì) 回復(fù) 2022-11-23
  • 1 回答
  • 0 關(guān)注
  • 155 瀏覽
慕課專欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)