草庐IT

json - 解码 JSON 时指向接口(interface)的指针与持有指针的接口(interface)

coder 2023-07-02 原文

考虑以下结构和接口(interface)定义。

type Foo interface {
    Operate()
}

type Bar struct {
    A int
}

func (b Bar) Operate() {
    //...
}

现在,如果我们尝试执行以下 ( playground):

var x Foo = Bar{}
err := json.Unmarshal([]byte("{\"a\": 5}"), &x)
fmt.Printf("x: %+v\nerr: %s\n", x, err) 

我们得到以下输出:

x: {A:0}
err: json: cannot unmarshal object into Go value of type main.Foo

但是,通过将基础数据替换为结构类型,它会顺利进行(playground):

var x Foo = &Bar{}
err := json.Unmarshal([]byte("{\"a\": 5}"), &x)
fmt.Printf("x: %+v\nerr: %s\n", x, err)

输出:

x: &{A:5}    
err: %!s(<nil>)

但是,这让我很困惑。在我们对 Unmarshall 的调用中,我们仍然传递一个指向 x 的指针,根据我的理解,这应该足以让我们修改下面的 Bar。毕竟,指针只是内存中的地址。如果我们传递那个地址,我们应该能够修改它,不是吗?为什么第二个示例有效,而第一个示例无效?为什么作为指针的结构会产生很大的不同?

最佳答案

不同行为的根源在于,如果 json 包必须创建一个新值,该值必须是具体类型,不能是(非具体)接口(interface)类型.

让我们详细说明一下。

首先让我们检查您的第二个工作示例。 Foo 类型的变量 x 包装了 *Bar 类型的指针值。当您将 &x 传递给 json.Unmarshal() 时,json 包将获得一个 *Foo 指针值。指向接口(interface)的指针!不应该使用,但它在那里。 json 包将取消引用指针,并获取 *Bar 类型的包装值。由于这是一个非nil 指针,json 包可以而且将会继续使用它进行解码。都好! json 包将修改 pointed 值。

您的第一个示例发生了什么?

在您的第一个示例中,您的 x 类型的 Foo 变量包装了一个非指针结构值。 不能修改包装在接口(interface)中的值。

这是什么意思? json 包将再次收到类型为 *Foo 的值。然后它继续并取消引用它,并获得一个包装在接口(interface)中的 Bar 值。 Foo 界面中的Bar 值不能被修改。 json 包“传递”结果的唯一方法是创建一个实现 Foo 的新值,并将该值存储在最初传递的 * Foo 指向。但是不能创建 Foo 的值,它是一个非具体的接口(interface)类型。因此 unmarshal 返回错误。

一些补充。您的第二个工作示例:

var x Foo = &Bar{}
err := json.Unmarshal([]byte("{\"a\": 5}"), &x)
fmt.Printf("x: %+v\nerr: %s\n", x, err)

这是可行的,因为我们“准备”了一个非 nil *Bar 值来解码,所以 json 包不会必须自己创造值(value)。我们已经为 Foo 接口(interface)类型准备并传递了一个值(具体类型 *Bar 的值)。

如果我们像这样存储指向 x 的“类型化”nil:

var x Foo = &Bar{}
x = (*Bar)(nil)
err := json.Unmarshal([]byte("{\"a\": 5}"), &x)
fmt.Printf("x: %+v\nerr: %s\n", x, err)

我们将返回相同的错误(在 Go Playground 上尝试):

x: <nil>
err: json: cannot unmarshal object into Go value of type main.Foo

解释是一样的:json 包不能使用nil 指针来解码值。它将再次需要创建一个非具体类型 Foo 的值,但这是不可能的。只能创建具体类型的值。

关于json - 解码 JSON 时指向接口(interface)的指针与持有指针的接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50564341/

有关json - 解码 JSON 时指向接口(interface)的指针与持有指针的接口(interface)的更多相关文章

  1. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  2. ruby-on-rails - 如何使用 Rack 接收 JSON 对象 - 2

    我有一个非常简单的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":

  3. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  4. ruby - 用 YAML.load 解析 json 安全吗? - 2

    我正在使用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("

  5. ruby-on-rails - Rails 渲染带有驼峰命名法的 json 对象 - 2

    我在一个简单的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'

  6. ruby - 使用 JSON gem 将自定义对象转换为 JSON - 2

    我正在学习如何使用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方法,这样我就可以获

  7. ruby 变量作为同一对象(指针?) - 2

    >>a=5=>5>>b=a=>5>>b=4=>4>>a=>5如何将“b”设置为实际的“a”,以便在示例中,变量a也将变为4。谢谢。 最佳答案 classRefdefinitializeval@val=valendattr_accessor:valdefto_s@val.to_sendenda=Ref.new(4)b=aputsa#=>4putsb#=>4a.val=5putsa#=>5putsb#=>5当您执行b=a时,b指向与a相同的对象(它们具有相同的object_id).当你执行a=some_other_thing时,a将指向

  8. ruby-on-rails - 如何使用驼峰键名称从 Rails 返回 JSON - 2

    我正在构建一个带有Rails后端的JS应用程序,为了不混淆snake和camelcases,我想通过从服务器返回camelcase键名来规范化这一切。因此,当从API返回时,user.last_name将返回user.lastName。我如何实现这一点?谢谢!编辑:添加Controller代码classApi::V1::UsersController 最佳答案 我的方法是使用ActiveModelSerializer和json_api适配器:在你的Gemfile中,添加:gem'active_model_serializers'创建

  9. ruby-on-rails - 如何将数组输出为 JSON? - 2

    我有以下内容:@array.inspect["x1","x2","adad"]我希望能够将其格式化为:client.send_message(s,m,{:id=>"x1",:id=>"x2",:id=>"adad"})client.send_message(s,m,???????)如何在????????中获得@array输出?空间作为ID?谢谢 最佳答案 {:id=>"x1",:id=>"x2",:id=>"adad"}不是有效的散列,因为您有键冲突它应该是这样的:{"ids":["x1","x2","x3"]}更新:@a=["x1

  10. ruby - 使用 jbuilder 创建具有动态哈希键的 JSON - 2

    这里我想输出带有动态组名的json而不是单词组@tickets.eachdo|group,v|json.group{json.array!vdo|ticket|json.partial!'tickets/ticket',ticket:ticketend}end@ticket是这样的散列{a:[....],b:[.....]}我想要这样的输出{a:[.....],b:[....]} 最佳答案 感谢@AntarrByrd,这个问题有类似的答案:JBuilderdynamickeysformodelattributes使用上面的逻辑我已经

随机推荐