草庐IT

pointers - 将值传递给接口(interface){}

coder 2023-06-29 原文

以下代码并没有完全按照预期执行: https://play.golang.org/p/sO4w4I_Lle

我假设我像往常一样弄乱了一些指针/引用的东西,但是我希望我的...

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

...和encoding/json...

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

...以相同的方式运行(例如,更新作为第二个参数传递的引用)。

上面的例子是一个没有多大意义的最小复制器。这是为了让它在 Playground 上工作。然而,一个不太有意义的例子是这样的:

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]interface{} 的值一起工作,而这就是您传递给它的内容,您可以使用简单的 type assertion从中获取 map 指针,并将此指针传递给 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()也被定义为将目的地作为 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

这意味着还有另一种选择,即您可以使用 function type 的名为 unmarshalJSON 的变量, 只需简单地分配函数值 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{} 参数中获取指针,一旦获得该指针,您就可以更改 pointed 对象(“外部” map )。

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
}

关于pointers - 将值传递给接口(interface){},我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35449466/

有关pointers - 将值传递给接口(interface){}的更多相关文章

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

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

  2. ruby-on-rails - 如何将数据传递给部分? - 2

    K伙计们,所以我创建了这个赞成/反对的投票脚本(基本上就像stackoverflow上的那个),我试图向其中添加一些Ajax,这样页面就不会在您每次投票时都重新加载。我有两个Controller,一个叫grinder,一个叫votes。(磨床基本都是帖子)所以这是所有研磨机的索引(看起来像这样)这是该页面的代码。Listinggrinders"grinders/grinders")%>这就是我在views/grinders/_grinders.erb中的内容true)do|u|%>grinder.id%>"up"%>'create')%>true)do|d|%>grinder.id%>

  3. ruby-on-rails - Rails - 如何避免在 View 中使用 hidden_​​fields 将值传递给 Controller ​​? - 2

    有没有一种方法可以避免hidden_​​field方法将View中的值传递给Controller​​?出于安全原因,我更喜欢Controller方法。不幸的是,strong_parameters不支持值对@variables。EDIT6/181:00PMESTI'verenamedmygaragescontrollertoappointmentscars_controllernolongercreatesanewappointment(formallygarages).Anewappointmentiscreatedintheappointments_controller我目前的结构路

  4. ruby-on-rails - 如何在 RubyOnRails 中使用 'acts as nested set' 创建一个可排序的接口(interface) - 2

    我一直在为使用acts_as_list的模型实现一些不错的交互界面,这些界面可以对我的mRails应用程序中的列表进行排序。我有一个排序函数,在每次拖放之后使用sortable_elementscript.aculo.us函数调用并设置每条记录的位置。这是在拖放完成后处理排序的Controller操作示例:defsortparams[:documents].each_with_indexdo|id,index|Document.update_all(['position=?',index+1],['id=?',id])endend现在我正在尝试对嵌套集模型(acts_as_nested

  5. 你真正了解什么是接口测试么?接口实战一“篇”入魂 - 2

    最近在工作中,看到一些新手测试同学,对接口测试存在很多疑问,甚至包括一些从事软件测试3,5年的同学,在聊到接口时,也是一知半解;今天借着这个机会,对接口测试做个实战教学,顺便总结一下经验,分享给大家。计划拆分成4个模块跟大家做一个分享,(接口测试、接口基础知识、接口自动化、接口进阶)感兴趣的小伙伴记得关注,希望对你的日常工作和求职面试,带来一些帮助。注:文章较长有5000多字,希望小伙伴们认真看完,当然有些内容对小白同学不是太友好,如果你需要详细了解其中的一些概念或者名词,请在文章之后留言,后续我将针对大家的疑问,整理输出一些大家感兴趣的文章。随着开发模式的迭代更新,前后端分离已不是新的概念,

  6. ruby-on-rails - 在 Ruby on Rails 中为由外部 API 支持的模型使用 ActiveRecord 接口(interface) - 2

    我正在尝试在我的Rails应用程序中使用模型来从外部API检索信息。我想做的是以类似于ActiveRecord模型提供的方式(特别是关联,以及相同风格的可链接查询方法)访问我的数据模型(可能包含来自多个API调用的信息)。我最初的直觉是重新创建我想要的ActiveRecord部分并合并此API。不想“重新发明轮子”并确切地看到添加更多功能需要多少工作让我退后一步并重新评估如何处理这个问题。我找到了在没有表的情况下使用ActiveRecord的方法(请参阅:Railscast#193TablelessModel和博客文章here)并研究了ActiveRecord。因为ActiveMode

  7. ruby - Interface Builder 看不到 MacRuby 的 socket - 2

    我正在尝试使用XCode和InterfaceBuilder构建一个基本的helloworld应用程序。但是,在InterfaceBuilder中,我看不到我的socket可以连接起来。我转到对象检查器Pane的连接选项卡,它显示“NewReferencingOutlet”。我想知道我的代码是否有误。在这里classHelloWorldControllerattr_accessor:hello_label,:hello_button,:hellodefawakeFromNib@hello=trueenddefchangeLabel(sender)if@hello@hello_label.

  8. ruby - 你能在渲染过程中将 ruby​​ 对象传递给 haml 吗? - 2

    我正在尝试创建一个haml模板,该模板使用我的ruby​​应用程序中的一些数据来填充一些内容。是否可以将参数传递给haml以使其正确呈现?以下是我获取haml模板并呈现它的方式:template=File.open('path/to/template.haml')html=Haml::Engine.new(template.read).render那么,是否可以将对象从本地Ruby脚本传递到模板文件中,以便正确呈现页面?或者,我可以让haml文件拉入对象吗?如果这不起作用,我唯一的其他想法是将模板构建为本地字符串,这对我来说似乎更乏味。那么,是否有一种不同的编码模式可以更有效地完成这项

  9. [译]在C#中使用IComparable和IComparer接口 - 2

    原文:UsetheIComparableandIComparerinterfacesinVisualCSharp本文介绍了在VisualC#中如何使用IComparer和IComparable接口。概要本文同时讨论了IComparable和IComparer接口,原因有两点。这两个接口经常一起使用。虽然接口类似且名称相似,但它们却有不同的用途。如果你有一个支持IComparer的类型数组(例如字符串或整数),你可以对它进行排序而不需要提供任何对IComparer的显式引用(译注:意思是把一个IComparer的实现类作为参数传递给排序方法)。在这种情况下,数组元素会被转换为IComparer的

  10. ruby - Jekyll:如何将 Ruby 对象传递给模板? - 2

    例如,假设我想生成这个数组:random_numbers=[]1000.times{random_numbers并将其传递给模板,以便我可以从Liquid访问它:{%fornuminrandom_numbers%}...hereI'duselogicaroundthenumbertogeneratesomething.{%endfor%}注意:我想在Ruby中动态生成数组。在模板内部,我想要一个可以迭代的数组,我不需要字符串。这在Jekyll中如何完成? 最佳答案 好吧,你需要一个插件:https://github.com/mojo

随机推荐