57

请参阅此操场片段

相关代码:

type somethingFuncy func(int) bool

func funcy(i int) bool {
    return i%2 == 0
}

var a interface{} = funcy

func main() {

    _ = a.(func(int) bool)  // Works

    fmt.Println("Awesome -- apparently, literally specifying the func signature works.")

    _ = a.(somethingFuncy)  // Panics

    fmt.Println("Darn -- doesn't get here. But somethingFuncy is the same signature as func(int) bool.")
}

通过显式声明类型,第一个强制转换起作用。但第二个演员惊慌失措。为什么?有没有一种干净的方法可以转换为更长的 func 签名?

4

4 回答 4

82

tl;博士

对于类型断言(您使用的),只有实际类型很重要。所以somethingFuncy只有等于somethingFuncy而不是func(int) bool

解释

首先,这与选角无关。go中没有强制转换。有类型断言类型转换

您正在处理类型断言并假设与类型转换相同的条件成立。我在阅读您的问题时犯了同样的错误,但实际上行为存在巨大差异。

假设你有两种类型,比如说inttype MyInt int。这些是可转换的,因为它们都共享相同的基础类型(转换规则之一),所以这有效(play):

var a int = 10
var b MyInt = MyInt(a)

现在,假设a不是类型int而是类型interface{}play):

var a interface{} = int(10)
var b MyInt = MyInt(a)

编译器会告诉你:

无法将 (type interface {}) 转换为 MyInt 类型:需要类型断言

所以现在我们不再进行转换,而是断言。我们需要这样做(play):

var a interface{} = int(10)
var b MyInt = a.(MyInt)

现在我们遇到了与您的问题相同的问题。此断言因恐慌而失败:

恐慌:接口转换:接口是 int,而不是 main.MyInt

其原因在规范的类型断言部分中说明:

对于 interface type 和 type 的表达式 x T,主表达式x.(T) 断言x不是nil并且存储在其中的值x是 type T。该符号 x.(T)称为类型断言。 更准确地说,如果T不是接口类型,x.(T)则断言的动态类型x与类型相同T

所以int必须与 相同MyInt类型身份的规则规定(在其他规则中):

如果两个命名类型的类型名称源自相同的 TypeSpec,则它们是相同的。

由于intMyInt具有不同的声明(TypeSpecs),它们不相等并且断言失败。当您断言atoint时,断言有效。所以你在做什么是不可能的。

奖金:

实际的检查发生在这段代码中,它只是检查两种类型是否与预期的一样。

于 2013-10-25T00:25:18.530 回答
26

2017 年更新:

使用 Go 1.9 中的类型断言,您可以简单地添加=定义类型的位置。

type somethingFuncy = func(int) bool

这告诉编译器这somethingFuncyfunc(int) bool.

于 2017-11-20T19:10:56.127 回答
8

只是为了完成 nemo 的精彩回答,请注意,虽然您不能直接从interface{}给定动态类型(例如,int)的界面(ef,)跳转到另一种类型(例如,type MyInt int),但您可以一个接一个地执行这两个步骤:

  • 断言变量的动态类型是您所期望的;
  • 将该断言的结果转换为您选择的类型。

请注意,由于底层类型,顾名思义,是动态的,因此最好测试类型断言是成功还是失败。另一方面,类型转换的正确性由编译器强制执行。

这是您的游乐场代码段稍作修改:http ://play.golang.org/p/FZv06Zf7xi

于 2014-01-13T19:28:38.040 回答
1

我相信类型别名就是你想要的。提案被接受并且应该在 Go 1.9 中。IE。

TypeSpec = identifier [ "=" ] Type .

参考
https://github.com/golang/go/issues/18130
https://github.com/golang/proposal/blob/master/design/18130-type-alias.md

于 2017-07-15T10:26:32.540 回答