Pointers 将值传递给接口{}
短期 以下代码不完全符合预期: 我假设我像往常一样搞砸了一些指针/引用的东西,但是我希望我的Pointers 将值传递给接口{},pointers,go,interface,yaml,unmarshalling,Pointers,Go,Interface,Yaml,Unmarshalling,短期 以下代码不完全符合预期: 我假设我像往常一样搞砸了一些指针/引用的东西,但是我希望我的 func unmarshalJSON(in []byte, s interface{}) error 。。。和encoding/jsons func Unmarshal(data []byte, v interface{}) error …以相同的方式进行操作(例如,更新作为第二个参数传递的引用) Long 上面的例子是一个没有多大意义的最小复制器。这是为了让它在操场上发挥作用。然而,一个不太简
func unmarshalJSON(in []byte, s interface{}) error
。。。和encoding/json
s
func Unmarshal(data []byte, v interface{}) error
…以相同的方式进行操作(例如,更新作为第二个参数传递的引用)
Long
上面的例子是一个没有多大意义的最小复制器。这是为了让它在操场上发挥作用。然而,一个不太简单的例子是:
package main
import (
"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
- aoeu
oaeu:
- { 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
函数应提供与使用类型断言的yaml.Unmarshal
..相同的函数签名
在unmarshalJSON()
函数中,参数s
的行为类似于局部变量。当您为其分配某些内容时:
s = result
它只会更改局部变量的值
由于您希望它能够更改*map[string]接口{}
的值,而这正是您传递给它的内容,因此您可以使用一个简单的方法从它获取映射指针,并将此指针传递给json.Unmarshal()
:
在上尝试修改后的工作示例
只是把它传过去
另外请注意,这是完全不必要的,因为它也定义为将目的地作为接口{}
类型的值,这与您的定义相同。所以你甚至不必做任何事情,只需传递:
func unmarshalJSON(in []byte, s interface{}) error {
return json.Unmarshal(in, s)
}
试穿这个
使用函数类型的变量
有趣的是,请注意unmarshalJSON()
的签名和库函数json.Unmarshal()
是相同的:
// Yours:
func unmarshalJSON(in []byte, s interface{}) error
// json package
func Unmarshal(data []byte, v interface{}) error
这意味着还有另一个选项,即可以使用a的名为unmarshalJSON
的变量,只需分配函数值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)
}
}
var unmarshalJSON func([]byte, interface{}) error = json.Unmarshal
现在您有了一个函数类型的变量unmarshalJSON
,您可以像调用函数一样调用它:
err := unmarshalJSON(b, &s)
在上尝试此函数值
现在转到解组halyaml()
函数
在unmarshalyml()
中,您也犯了同样的错误:
s = cleanUpInterfaceMap(result)
这只会更改本地s
变量(参数)的值,不会“填充”传递到unmarshalyml()的映射(指针)。
使用上面详述的类型断言技术从s
接口{}
参数获取指针,一旦获得了指针,就可以更改指向的对象(“外部”映射)
使用类型断言
在unmarshalJSON()
函数中,参数s
的行为类似于局部变量。当您为其分配某些内容时:
s = result
它只会更改局部变量的值
由于您希望它能够更改*map[string]接口{}
的值,而这正是您传递给它的内容,因此您可以使用一个简单的方法从它获取映射指针,并将此指针传递给json.Unmarshal()
:
在上尝试修改后的工作示例
只是把它传过去
另外请注意,这是完全不必要的,因为它也定义为将目的地作为接口{}
类型的值,这与您的定义相同。所以你甚至不必做任何事情,只需传递:
func unmarshalJSON(in []byte, s interface{}) error {
return json.Unmarshal(in, s)
}
试穿这个
使用函数类型的变量
有趣的是,请注意unmarshalJSON()
的签名和库函数json.Unmarshal()
是相同的:
// Yours:
func unmarshalJSON(in []byte, s interface{}) error
// json package
func Unmarshal(data []byte, v interface{}) error
这意味着还有另一个选项,即可以使用a的名为unmarshalJSON
的变量,只需分配函数值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)
}
}
var unmarshalJSON func([]byte, interface{}) error = json.Unmarshal
现在您有了一个函数类型的变量unmarshalJSON
,您可以像调用函数一样调用它:
err := unmarshalJSON(b, &s)
在上尝试此函数值
现在转到解组halyaml()
函数
在unmarshalyml()
中,您也犯了同样的错误:
s = cleanUpInterfaceMap(result)
这只会更改本地s
变量(参数)的值,不会“填充”传递到unmarshalyml()的映射(指针)。
使用上面详述的类型断言技术从s
接口{}
参数获取指针,一旦获得了指针,就可以更改指向的对象(“外部”映射)
谢谢@icza!您介意看一下我提供的“长”示例吗?我理解你所指出的,但还没有找到一种方法将其应用于unmarshalYAML()。@sontags但这正是发生的事情。或多或少在上面的示例中,我没有检查是否传递了map或
nil
map值,它只会“覆盖”传递的map变量。但是它从外部是可见的。@sontags另外,您可以检查*dest
是否不是nil
,如果不是,您可以向该映射添加(复制)值,但更清楚的是,只需赋值,因为该映射可能已经包含值,从而进一步混淆这些元素的来源(例如,我们已经在地图中,或者是解组的结果)。很好!我花了很长时间才写下我的评论,同时你更新了你的答案!非常感谢!谢谢@icza!你介意看看我提供的“long”示例吗?我理解你指的是什么,但还没有找到将此应用于解组的方法()然而…@sontags但这正是发生的事情。或多或少。在上面的示例中,我不检查是否传递了map或nil
map值,它只会“覆盖”传递的map变量。但它将从外部可见。@sontags另外,您可以检查*dest