当使用 interface{} 作为函数参数类型,给定非指针类型,并使用 json.Unmarshal 时,我在 Go 中遇到了一个错误。
因为一段代码抵得上千字,这里有一个例子:
package main
import (
"encoding/json"
"fmt"
)
func test(i interface{}) {
j := []byte(`{ "foo": "bar" }`)
fmt.Printf("%T\n", i)
fmt.Printf("%T\n", &i)
json.Unmarshal(j, &i)
fmt.Printf("%T\n", i)
}
type Test struct {
Foo string
}
func main() {
test(Test{})
}
哪些输出:
main.Test
*interface {}
map[string]interface {}
json.Unmarshal 将我的结构转换为 map[string]interface{} oO...
后面的小阅读解释了一些,interface{}本身就是一种类型,而不是某种无类型的容器,它解释了*interface{},并且事实上,json.Unmarshal 无法获取初始类型,并返回了一个 map[string]interface{}..
来自 Unmarshal 文档:
To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value: [...]
如果我像这样传递一个指向测试函数的指针,它就可以工作:
func test(i interface{}) {
j := []byte(`{ "foo": "bar" }`)
fmt.Printf("%T\n", i)
fmt.Printf("%T\n", &i)
json.Unmarshal(j, i)
fmt.Printf("%T\n", i)
fmt.Println(i)
}
func main() {
test(&Test{})
}
哪些输出:
*main.Test
*interface {}
*main.Test
&{bar}
很酷,数据已解码,现在在第二个片段中,我在调用 Unmarshal 时删除了 &。因为我在 i 中有一个 *Test,所以没用。
所以在所有逻辑中,如果我在调用 Unmarshal 时将 & 放回 i 它应该会弄乱 i 再次键入。但是没有。
如果我运行:
func test(i interface{}) {
j := []byte(`{ "foo": "bar" }`)
fmt.Printf("%T\n", i)
fmt.Printf("%T\n", &i)
json.Unmarshal(j, &i)
fmt.Printf("%T\n", i)
fmt.Println(i)
}
func main() {
test(&Test{})
}
它仍然有效:
*main.Test
*interface {}
*main.Test
&{bar}
现在我没有谷歌搜索查询了。
最佳答案
interface{} 是任何值和任何类型的包装器。一个接口(interface)示意性地包装了一个(value; type)对,一个具体的值和它的类型。有关此的更多详细信息:The Laws of Reflection #The representation of an interface .
json.Unmarshal()已经采用 interface{} 类型的值:
func Unmarshal(data []byte, v interface{}) error
因此,如果您已经有一个 interface{} 值(test() 函数的 i interface{} 参数),不要'尝试获取它的地址,按原样传递它。
另请注意,对于任何要修改存储在 interface{} 中的值的包,您都需要将指针传递给它。所以 i 中应该是一个指针。所以正确的场景是将*Test传递给test(),在test()内部传递i给json.Unmarshal()(不获取其地址)。
当 i 包含 *Test 并且您传递 &i 时,它将起作用,因为 json 包将简单地取消引用 *interface{} 指针,并找到一个 interface{} 值,它包装了一个 *Test 值。它是一个指针,所以一切都很好:将 JSON 对象解码为指向的 Test 值。
当 i 包含 Test 并且您传递 &i 时,与上面相同:*interface{}被取消引用,因此它找到一个包含非指针的接口(interface){}:Test。由于 json 包无法解码为非指针值,因此它必须创建一个新值。由于传递给 json.Unmarshal() 函数的值是 *interface{} 类型,它告诉 json 包解码数据转换为 interface{} 类型的值。这意味着 json 包可以自由选择要使用的类型。默认情况下,json 包将 JSON 对象解码为 map[string]interface{} 值,因此这就是创建和使用的内容(并最终放入由您传递的指针:&i)。
总而言之,避免使用指向接口(interface)的指针。而是将指针“放入”接口(interface)(接口(interface)值应该包装指针)。如果您已有一个包含指针的接口(interface){},只需将其传递即可。
关于json - Golang interface{} 类型误解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38829941/
在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s
我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain
我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":
我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("
我在一个简单的RailsAPI中有以下Controller代码:classApi::V1::AccountsControllerehead:not_foundendendend问题在于,生成的json具有以下格式:{id:2,name:'Simpleaccount',cash_flows:[{id:1,amount:34.3,description:'simpledescription'},{id:2,amount:1.12,description:'otherdescription'}]}我需要我生成的json是camelCase('cashFlows'而不是'cash_flows'
我正在学习如何使用JSONgem解析和生成JSON。我可以轻松地创建数据哈希并将其生成为JSON;但是,在获取一个类的实例(例如Person实例)并将其所有实例变量放入哈希中以转换为JSON时,我脑袋放屁。这是我遇到问题的例子:require"json"classPersondefinitialize(name,age,address)@name=name@age=age@address=addressenddefto_jsonendendp=Person.new('JohnDoe',46,"123ElmStreet")p.to_json我想创建一个.to_json方法,这样我就可以获