在 Swift 3 中,为什么函数的 void 返回值 -> () 只是偶尔推断,但其他时候必须声明?



请考虑以下代码:

typealias bar = ()->()
let foo:bar = { baz -> () in
print("foobar")
return ()
}
let baz = foo()
print("(baz)")

哪些输出:

福巴

((

现在,如果我们更改此行:

let foo:bar = { baz -> () in

对此:

let foo:bar = { baz in

。然后什么也没发生。即,-> ()由编译器推断。(注意:如果我们省略return ()编译器也很高兴。

但是,与此同时,如果我们更改此行:

typealias bar = ()->()

对此:

typealias bar = ()

。然后编译器吓坏了,自杀了。为什么?

这似乎与 Swift 的文档相冲突,后者将()(又名Void(定义为:

未显式指定返回类型的函数的返回类型

根据该语句,由于typealias bar = ()->()显式指定了返回类型,因此根据定义,它不能返回()- 但它确实如此!这是完全不合逻辑和自相矛盾的。

有人可以向我解释一下他们对此的想法吗?这里的理由是什么?

如果->()应该总是被推断出来,那么为什么还要有它呢?为什么不直接说()总是一个函数,这样()()总是返回()

如果我没记错的话,这就是你所说的情况:

typealias bar = ()
let foo: bar = { baz -> () in
print("foobar")
return ()
}

赋值的右手是类型() -> ()的闭包,它是未计算的。foo应该有类型 bar (()(,但只有在评估闭包时才会出现这种情况,例如:

let foo: bar = { baz -> () in
print("foobar")
return ()
}()

我喜欢亚历山大的回答,但这里有另一个角度可能会有所帮助。

使用typealias bar = ...声明,您将定义一个类型。该定义必须是完整和明确的。否则,类型系统将无法检查稍后声明的内容是否为该类型的成员。此声明提供了类型的完整签名 -- 对于函数/闭包类型,这意味着它的参数类型集和返回类型,即使两者都是Void(也称为()(。

使用let foo: bar = ...,您将声明一个值并声明它必须是该类型的成员。由于类型定义的部分是已知的(由于类型别名(,因此在声明类型的成员时无需重复它们:

闭包不需要
  • 声明其返回类型,因为这是闭包符合的函数类型的一部分。您可以在闭包中return预期类型的任何值。(或者,由于您的函数类型定义了返回类型Void,因此您不能return任何内容。
  • 您的闭包不需要声明其参数的类型,因为类型别名也已经这样做了。(或者,由于唯一参数的类型是Void,因此根本不需要声明参数。

在定义类型已知的闭包时,省略闭包语法是 Swift 的类型推断功能之一。你可以认为它等同于,如果你有一个enum Foo { case one, two, three }和一个func bar(_ foo: Foo),你被允许在通话中只传递.one(bar(.one)(。Foo.one是该常量的完全限定名称,但只要.one就足够了,因为 Swift 可以推断出Foo类型。

最新更新