

実現したいことは、json.Unmarshalを単純にラップした関数の作成なのですが、Unmarshalに渡す構造体はinterface{}型の引数として受け取りたいです。  
しかし以下のように実現できていません。どのような方法があるでしょうか。

**ステップ１：ベースとなるコード**

[code]

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    type User struct {
        Name string `json:"name"`
    }
    
    func main() {
    
        j := []byte(`{"name": "ando"}`)
    
        var user User
        if err := json.Unmarshal(j, &user); err != nil {
            panic(err)
        }
    
        fmt.Printf("%#v", user)
        //=> main.User{Name:"ando"}
    }
    
[/code]

**ステップ２：interface{}型をそのまま渡して失敗**

json.Unmarshalをラップした、unmarshal関数を作成。しかし、interface{}型をそのままUnmarshalに渡してしまったので、map型で返ってきてしまった。

[code]

    func main() {
    
        bs := []byte(`{"name": "ando"}`)
    
        var user User
    
        _, err := unmarshal(bs, user)
        if err != nil {
            panic(err)
        }
    
    }
    
    func unmarshal(bs []byte, st interface{}) (interface{}, error) {
    
        if err := json.Unmarshal(bs, &st); err != nil {
            return nil, err
        }
    
        fmt.Printf("%#v\n", st)
        //=> map[string]interface {}{"name":"ando"}
    
        return st, nil
    }
    
[/code]

**ステップ３：reflectパッケージで元の構造体に復元したつもりが失敗**

初めてreflectパッケージを使い、見よう見まねでinterface{}型から元の構造体を復元したつもりが、エラーにはならないが正常にデコードされない。

[code]

    import (
        "encoding/json"
        "fmt"
        "reflect"
    )
    
    func unmarshal(bs []byte, st interface{}) (interface{}, error) {
    
        // 元の構造体を復元しようとしたつもり
        rv := reflect.New(reflect.TypeOf(st)).Elem()
    
        if err := json.Unmarshal(bs, &rv); err != nil {
            return nil, err
        }
    
        fmt.Printf("%#v\n", rv)
        //=> main.User{Name:""} ※値が初期値のまま
    
        return rv, nil
    }
    
[/code]


CC BY-SA 4.0
2018-10-23T04:30:40.583
49554
2021-08-19T00:05:35.497
19759
question
go
interface{}型で受け取った引数を元の型に戻してjson.Unmarshalしたい


自己回答です。（metropolisさんのコメントから）

まだしっかりと理解できてないのですが、以下で実現できましたのでとりあえず回答として残します。

[code]

    package main
    
    import (
        "encoding/json"
        "fmt"
        "reflect"
    )
    
    type User struct {
        Name string `json:"name"`
    }
    
    func main() {
        bs := []byte(`{"name": "ando"}`)
    
        u, err := unmarshal(bs, User{})
        if err != nil {
            panic(err)
        }
    
        user := u.(User)
        fmt.Printf("%s", user.Name)
        //=> ando
    }
    
    func unmarshal(bs []byte, st interface{}) (interface{}, error) {
        rv := reflect.New(reflect.TypeOf(st)).Interface()
        if err := json.Unmarshal(bs, &rv); err != nil {
            return nil, err
        }
        return reflect.ValueOf(rv).Elem().Interface(), nil
    }
    
[/code]


CC BY-SA 4.0
2018-10-23T07:06:22.663
49559
2018-10-23T07:06:22.663
19759
49554
answer