如何返回指定返回值的子类型(在本例中为interface {})?

时间:2017-04-26 00:29:46

标签: go

我有一个接口,它定义了一个类型为func(interface{}, proto.Message) interface{}的参数,并且我试图将func reduceMsg(a interface{}, b proto.Message) []*PersistentData类型的内容传递给它。这会导致以下编译器错误:

Cannot use reduceMsg (type func(a interface{}, b proto.Message) []*PersistentData as type func(interface{}, proto.Message) interface{}

出现此错误的原因是什么,我该如何解决?似乎返回比interface{}更合适的类型应该是合法的。这是一个简单的完整示例,说明了这个问题:

package main

import "fmt"

func main() {
    var t func() interface{} = func() []string { return []string{} }
    fmt.Println(t)
}

2 个答案:

答案 0 :(得分:2)

对象的类型是整个函数签名。如果签名不匹配,则它不是同一类型,不能以这种方式分配。

任何东西都可以分配给空接口,因为所有类型都满足接口,但在你的问题中,类型都不是空接口,你只需要一个返回空接口的函数。

不是因为函数的一部分可以分配给另一个函数而是因为它是相同的。类型是整个函数签名。我认为无法将int分配给int8背后的逻辑是相同的。您可以根据需要进行投射,但是对于go,它们是单独的类型,您需要处理必要的转换才能分配它们。

您可以做的是更改第二个函数签名以返回如下所示的空接口:

func(interface{}, proto.Message) interface{}

func reduceMsg(a interface{}, b proto.Message) interface{} {
    var a []*PersistentData
    // do something here
    return a
}

这样功能签名是相同的,因此它考虑相同的类型,并且您返回[]*PersistentData。当然,在使用它之前你需要做一个类型断言,因为程序会将它视为{}interface,因为这是函数返回的类型。

答案 1 :(得分:1)

Referencing the spec

  

在赋值中,每个值必须可赋值给它所分配的操作数的类型,具有以下特殊情况:

     
      
  • 可以将任何类型的值分配给空白标识符。
  •   
  • 如果为接口类型的变量或空标识符分配了无类型常量,则首先将常量转换为其默认类型。
  •   
  • 如果为接口类型的变量或空标识符分配了无类型的布尔值,则首先将其转换为bool类型。
  •   

转让性

  

在任何这些情况下,值x都可分配给T类型的变量(" x可分配给T"):

     
      
  • x的类型与T相同。
  •   
  • x的类型V和T具有相同的基础类型,并且V或T中的至少一个不是命名类型。
  •   
  • T是接口类型,x实现T。
  •   
  • x是双向通道值,T是通道类型,x类型V和T具有相同的元素类型,并且V或T中的至少一个不是命名类型。
  •   
  • x是预先声明的标识符nil,T是指针,函数,切片,地图,通道或接口类型。
  •   
  • x是一个无类型常量,可由类型T的值表示。
  •   

通常,Go不允许您隐式地将值从一种类型转换为另一种类型,除了能够使用具体类型的对象,就好像它们是接口(它们实现的)。

在这种特殊情况下,由于你的函数实际上没有返回interface{},编译器必须做一些额外的工作来将返回值包装为interface{}并返回它;如果你真的想要完成你正在尝试的事情,你可以自己明确地做到这一点:

type Foo struct {
    X int
}
func create(x int) Foo {
    return Foo{X: x}
}
func main() {
    var f func(int) interface{} = func(x int) interface{} {
        return create(x)
    }
}

基本上(显式地)执行您希望运行时隐式执行的包装操作。