为了账号安全,请及时绑定邮箱和手机立即绑定

将值传递给接口{}

将值传递给接口{}

Go
万千封印 2021-12-13 18:50:43
短的以下代码并不完全符合预期:https : //play.golang.org/p/sO4w4I_Lle我假设我像往常一样弄乱了一些指针/引用的东西,但是我希望我的......func unmarshalJSON(in []byte, s interface{}) error……还有encoding/json……func Unmarshal(data []byte, v interface{}) error ...以相同的方式运行(例如,更新作为第二个参数传递的引用)。长上面的例子是一个没有多大意义的最小复制器。这是为了让它在操场上工作。然而,一个不那么有意义的例子是这样的:package mainimport (    "fmt"    "gopkg.in/yaml.v2")func unmarshalYAML(in []byte, s interface{}) error {    var result map[interface{}]interface{}    err := yaml.Unmarshal(in, &result)    s = cleanUpInterfaceMap(result)    // s is printed as expected    fmt.Println(s) // map[aoeu:[test aoeu] oaeu:[map[mahl:aoec tase:aoeu]]]    return err}func cleanUpInterfaceArray(in []interface{}) []interface{} {    out := make([]interface{}, len(in))    for i, v := range in {        out[i] = cleanUpMapValue(v)    }    return out}func cleanUpInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {    out := make(map[string]interface{})    for k, v := range in {        out[fmt.Sprintf("%v", k)] = cleanUpMapValue(v)    }    return out}func cleanUpMapValue(v interface{}) interface{} {    switch v := v.(type) {    case []interface{}:        return cleanUpInterfaceArray(v)    case map[interface{}]interface{}:        return cleanUpInterfaceMap(v)    case string:        return v    default:        return fmt.Sprintf("%v", v)    }}func main() {    s := make(map[string]interface{})    b := []byte(`---aoeu:- test- aoeuoaeu:- { tase: aoeu, mahl: aoec}`)    err := unmarshalYAML(b, &s)    if err != nil {        panic(err)    }    // s is still an empty map    fmt.Println(s) // map[]}这个想法是将 YAML 解组为map[string]interface{}(而不是map[interface{}]interface{})以便允许序列化为 JSON(其中标识符需要是字符串)。该unmarshalYAML功能应该提供同样的FUNC signture为yaml.Unmarshal...
查看完整描述

1 回答

?
炎炎设计

TA贡献1808条经验 获得超4个赞

使用类型断言

在您的unmarshalJSON()函数中,参数的s行为类似于局部变量。当你为它分配一些东西时:


s = result

它只会改变局部变量的值。


由于您希望它改变 a 的值*map[string]interface{}并且这就是您传递给它的值,因此您可以使用简单的类型断言从中获取映射指针,并将此指针传递给json.Unmarshal():


func unmarshalJSON(in []byte, s interface{}) error {

    if m, ok := s.(*map[string]interface{}); !ok {

        return errors.New("Expecting *map[string]interface{}")

    } else {

        return json.Unmarshal(in, m)

    }

}

在Go Playground上尝试修改后的工作示例。


只是传递

还要注意,但是这完全没有必要,因为json.Unmarshal()它也被定义为将目的地作为 type 的值interface{},与您拥有的相同。所以你甚至不需要做任何事情,只需传递它:


func unmarshalJSON(in []byte, s interface{}) error {

    return json.Unmarshal(in, s)

}

在Go Playground上试试这个。


带有函数类型的变量

有趣的是,您和库函数的签名是相同的:unmarshalJSON()json.Unmarshal()


// Yours:

func unmarshalJSON(in []byte, s interface{}) error


// json package

func Unmarshal(data []byte, v interface{}) error

这意味着还有另外一个选择,那就是你可以使用一个命名的变量unmarshalJSONa的函数类型,并只分配函数值json.Unmarshal:


var unmarshalJSON func([]byte, interface{}) error = json.Unmarshal

现在你有一个unmarshalJSON函数类型的变量,你可以像调用函数一样调用它:


err := unmarshalJSON(b, &s)

在Go Playground上试试这个函数值。


现在开始你的unmarshalYAML()功能

在你unmarshalYAML()你犯了同样的错误:


s = cleanUpInterfaceMap(result)

这只会更改您的局部s变量(参数)的值,而不会“填充”传递给unmarshalYAML().


使用上面详述的类型断言技术从s interface{}参数中获取指针,一旦获得指针,就可以更改指向的对象(“外部”映射)。


func unmarshalYAML(in []byte, s interface{}) error {

    var dest *map[string]interface{}

    var ok bool

    if dest, ok = s.(*map[string]interface{}); !ok {

        return errors.New("Expecting *map[string]interface{}")

    }


    var result map[interface{}]interface{}

    if err := yaml.Unmarshal(in, &result); err != nil {

        return err

    }

    m := cleanUpInterfaceMap(result)


    // m holds the results, dest is the pointer that was passed to us,

    // we can just set the pointed object (map):

    *dest = m

    return nil

}


查看完整回答
反对 回复 2021-12-13
  • 1 回答
  • 0 关注
  • 235 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号