2017-08-30 16 views
4

文字列構造体に整数を逆シリアル化するのに苦労しています。 構造体フィールドは文字列であり、私のライブラリのユーザから割り当てられることが期待されています。だから私はそれを文字列にしたいのです。なぜなら、データベースに書き込む目的のために、私は実際に内部の値を気にしないからです。 ユーザはテキストを提供することができますが、整数だけを割り当てるものもあります。私は有効なJSON値で終わる文字列の代わりに整数であるため、Fooのフィールドに構造体の中にデシリアライズしませんたまにJSON非整数フィールドを文字列に変換する

type Test struct { 
    Foo string 
} 

は、この構造体を考えてみましょう

{ "foo": "1" } // works 
{ "foo": 1 } // doesn't 

json.Unmarshalは、次のエラーで爆破します:https://play.golang.org/p/4Qau3umaVmjson: cannot unmarshal number into Go struct field test.Foo of type string

は、再生を参照してください。

他のJSONライブラリ(これ以外の言語でも)では、ターゲットフィールドが文字列で、整数を取得する場合は、通常、デシリアライザはintを文字列にラップして処理します。これはGoで達成できますか?

私は本当にデータは、私がjson.Unmarshal unsensitiveこれに加える必要があるに来る方法を制御することはできませんので

- 他のソリューションは、不タイプアサーションなどで自分のコードを複雑 interface{}としてはFooを定義することです。..

これを行う方法に関するアイデア?私は基本的に逆を必要としますjson:",string"

+0

あなたは[json.Unmarshaler](https://golang.org/pkg/encoding/json/#Unmarshaler)インターフェースを実装することができます。 – mkopriva

答えて

5

大きな構造体を処理するには、使用することができます:

未知のタイプを処理する最も簡単な方法は、中間構造にJSONをnnmarshal、とデシリアライズ時に型アサーションと検証を処理することです埋め込み。

おそらく以前に設定されたフィールド値を破棄しないように更新されました。

func (t *T) UnmarshalJSON(d []byte) error { 
    type T2 T // create new type with same structure as T but without its method set! 
    x := struct{ 
     T2 // embed 
     Foo json.Number `json:"foo"` 
    }{T2: T2(*t)} // don't forget this, if you do and 't' already has some fields set you would lose them 

    if err := json.Unmarshal(d, &x); err != nil { 
     return err 
    } 
    *t = T(x.T2) 
    t.Foo = x.Foo.String() 
    return nil 
} 

https://play.golang.org/p/BytXCeHMvt

+3

良い例(でもそれは[エイリアス](https://golang.org/ref/spec#Alias_declarations)ではない) – JimB

+0

私はそれが1.9エイリアスではないことを知っていますが、これは前にエイリアシングと呼ばれていますか? – mkopriva

+3

いいえ、新しいタイプを作成するため、エイリアスと呼ばれることはありません。過去に別名を「エイリアス」と呼んだわけではありませんが、特に実際のエイリアスのアイデアが生まれてからは、何年もこの問題を踏まえて頑張っています。以前はそれぞれ 'uint8'と' int32'の 'byte'と' rune'でした。 – JimB

1

json.Unamrshalerインターフェイスを実装することによって、データ構造がどのようにunamrshaledになるかをカスタマイズすることができます。

type test struct { 
    Foo string `json:"foo"` 
} 

func (t *test) UnmarshalJSON(d []byte) error { 
    tmp := struct { 
     Foo interface{} `json:"foo"` 
    }{} 

    if err := json.Unmarshal(d, &tmp); err != nil { 
     return err 
    } 

    switch v := tmp.Foo.(type) { 
    case float64: 
     t.Foo = strconv.Itoa(int(v)) 
    case string: 
     t.Foo = v 
    default: 
     return fmt.Errorf("invalid value for Foo: %v", v) 
    } 

    return nil 
} 

+1

ありがとう - 私もそれについて考えました。しかし、これは本当に大きな構造体です。問題のあるフィールドに対してのみどのように非マーシャリングを実装できるのでしょうか? – Tigraine

+0

@Tigraine:はいmkoprivaはその良い例を作った – JimB

関連する問題