【问题标题】:Go: Passing a return value via an interface{} pointerGo:通过 interface{} 指针传递返回值
【发布时间】:2016-04-06 09:17:18
【问题描述】:

我有一个看起来像这样的函数:

func Foo(result interface{}) error {
     ...
     json.Unmarshal([]byte(some_string), result)
     ...
}

这样称呼:

var bar Bar
Foo(&bar)

通常,Foo 获取一个字符串,然后将其解组到结果中。但是,现在我需要更新它,以便 Foo 有时会从另一个源加载数据并返回它。

type Loader func() (interface{})

func Foo(result interface{}, Loader load) error {
     ...
     data := load()
     // result = data ???
     ...
}

我有什么方法可以将这个新值分配给结果?我发现我可以将数据编组为字符串,然后将其解组为有效的结果,但我无法想象这是最好的方法。

【问题讨论】:

  • Foo 的第一个版本不起作用。解组到结果,而不是指向结果的指针。 json.Unmarshal([]byte(some_string), result).

标签: go interface


【解决方案1】:

你可以的,

p := result.(*Bar)
*p = data

第一行是type assertion

第二个将data 分配给取消引用的指针。将值分配给取消引用的指针会更改引用地址处的值。

由于您不知道 resultdata 的基础类型,因此您能做的最好的事情就是使用类型断言开关。

switch v := data.(type) {
case Bar:
    // If 'data' is of type 'Bar'
    p, ok := result.(*Bar)
    if(!ok){
        // This means inputs were bad.
        // 'result' and 'data' should both have the same underlying type.
        fmt.Println("underlying types mismatch")
        break;
    }

    *p = v

case Baz:
    // If 'data' is of type 'Baz'
    // Equivalent of above for 'Baz'
}

参见switch statement类型开关

【讨论】:

  • 唯一的问题是我不知道 Foo 内部结果的具体类型。这就是我使用 interface{} 的原因。我需要使用反射来解决这个问题吗?
  • 比尔,对不起,我忽略了它。用我能想到的最佳解决方案更新了答案。我希望你已经考虑过使用这个 API。也许您可以将其更改为仅返回数据而不是将其分配给指针?
  • 无论如何我都需要为反序列化案例传递一个引用的结构,无论我如何重构,我总是会最终到达加载结构或反序列化的地步细绳。它最终会变成 foo(result interface{}, load Loader) (interface{}, error) 之类的东西,这很好,但不像我希望的那样干净。
猜你喜欢
  • 2014-01-17
  • 2015-03-28
  • 1970-01-01
  • 2017-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-31
相关资源
最近更新 更多