Как использовать строковое значение json для получения значения йоты? - PullRequest
0 голосов
/ 17 февраля 2019

У меня есть пакет constutil, в котором я определил некоторые значения const, используя iota.

package constutil

type UserType uint

const (
    Free UserType = iota + 1
    Premium UserType
    ...
)

С json Я получу {"user": "Premium", ...}.Теперь мне нужно сохранить значение пользователя, например, для Premium это 2.Я пытался получить значение следующим образом:

constutil.(req.User)

Но это не сработало, так как req.User возвращает string вроде: "Premium".

Я могу просто сделать этоиспользуя map[string]uint.Но есть ли способ сделать это, используя iota?

Ответы [ 2 ]

0 голосов
/ 17 февраля 2019

Не думайте, что есть какой-либо встроенный способ отображения между iota значениями и строками.Существуют некоторые инструменты, которые генерируют код для сопоставления.

Я был в подобных ситуациях и делал что-то подобное, когда не хотел зависеть от генераторов или других инструментов.Надеюсь, что это послужит началом чего-то.

https://play.golang.org/p/MxPL-0FVGMt

package main

import (
    "encoding/json"
    "fmt"
)

type UserType uint

const (
    UserTypeFree UserType = iota
    UserTypePremium
)

var UserTypeToString = map[UserType]string{
    UserTypeFree:    "Free",
    UserTypePremium: "Premium",
}

var UserTypeFromString = map[string]UserType{
    "Free":    UserTypeFree,
    "Premium": UserTypePremium,
}

func (ut UserType) String() string {
    if s, ok := UserTypeToString[ut]; ok {
        return s
    }
    return "unknown"
}

func (ut UserType) MarshalJSON() ([]byte, error) {
    if s, ok := UserTypeToString[ut]; ok {
        return json.Marshal(s)
    }
    return nil, fmt.Errorf("unknown user type %d", ut)
}

func (ut *UserType) UnmarshalJSON(text []byte) error {
    var s string
    if err := json.Unmarshal(text, &s); err != nil {
        return err
    }
    var v UserType
    var ok bool
    if v, ok = UserTypeFromString[s]; !ok {
        return fmt.Errorf("unknown user type %s", s)
    }
    *ut = v
    return nil
}

func main() {
    var ut UserType

    json.Unmarshal([]byte(`"Free"`), &ut)

    fmt.Printf("%#v %v \n", ut, ut)

    b, _ := json.Marshal(ut)

    fmt.Printf("%v\n", string(b))

}
0 голосов
/ 17 февраля 2019

Лучше всего использовать константную строку для такого случая использования Enum.

type UserType string

const(
  Premium UserType = "Premium"
)

ИЛИ определить пользовательский маршал / unmasrshal:

package main

import (
    "fmt"
    "encoding/json"
)

type UserType uint

func (u UserType) String() string{
    return "Premium"
}

const(
  Premium UserType = 1
)

type User struct{
    T UserType `json:"type"`
}

func (u *User) MarshalJSON() ([]byte, error) {
    return json.Marshal(&struct {
        T string
    }{
        T:    fmt.Sprint(u.T),
    })
}

func (u *User) UnmarshalJSON(data []byte) error {
    aux := &struct {
        T string `json:"type"`
    }{  }
    if err := json.Unmarshal(data, &aux); err != nil {
        return err
    }
    fmt.Println(aux.T)
    switch aux.T{
    case "Premium":
        u.T = Premium
    }
    return nil
}


func main() {
    b := []byte(`{"type":"Premium"}`)
    x := new(User)
    if err := json.Unmarshal(b, x); err != nil{
        fmt.Printf("err: %v\n", err)
    }
    fmt.Printf("unmasrshalled: %v\n", *x)
    fmt.Printf("type: %d\n", x.T)
    b, _ = json.Marshal(x)
    fmt.Printf("marshalled: %v\n", string(b))

}
...