在Swift 3、为什么函数的void return值,->(),只是有时推断,而其他时候必须声明?

In Swift 3, why is the void return value of functions, -> (), only sometimes inferred, but other times, must be declared?

考虑以下代码:

typealias bar = ()->()

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

let baz = foo()

print("\(baz)")

输出:

foobar

()

现在,如果我们改变这一行:

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

对此:

let foo:bar = { baz in

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

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

typealias bar = ()->()

对此:

typealias bar = ()

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

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

The return type of functions that don’t explicitly specify a return type

根据该声明,由于 typealias bar = ()->() 明确指定了 return 类型,因此根据定义,它不能 return () — 但它确实如此!这完全不合逻辑,自相矛盾。

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

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

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

typealias bar = ()

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

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

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

我喜欢 ,但这是另一个可能有用的角度。

使用 typealias bar = ... 声明,您正在定义一个类型。该定义必须完整且明确。否则,类型系统将无法检查您稍后声明的内容是否是该类型的成员。这个声明提供了类型的完整签名——对于 function/closure 类型,这意味着它的参数类型集和它的 return 类型,即使两者都是 Void(又名 ()).

使用 let foo: bar = ... 您声明一个值并声明它必须是该类型的成员。因为类型的部分定义是已知的(多亏了类型别名),所以在声明类型的成员时不需要重复它们:

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

在定义一个已知类型的闭包时省略一些闭包语法是Swift的类型推断特性之一。您可以将其视为等同于,如果您有一个 enum Foo { case one, two, three } 和一个 func bar(_ foo: Foo),您可以在调用 (bar(.one)) 中仅传递 .oneFoo.one 是该常量的完全限定名称,但仅 .one 就足够了,因为 Swift 可以推断出 Foo 类型。