为什么Swift编译器不能推断出这个闭包的类型?

vrw*_*wim 8 type-inference swift

所以我编写代码来区分我的应用程序的多个版本:

static var jsonURLNL =  {
    if ProcessInfo.processInfo.environment["CONSUMER"] != nil {
        return URL(string: "consumerURL")!
    }
    return URL(string: "professionalURL")!
}()
Run Code Online (Sandbox Code Playgroud)

但是我遇到了编译器错误:

无法推断出复杂的闭包返回类型; 添加显式类型以消除歧义

为什么Swift编译器不能知道这会返回一个URL?我认为在这种情况下这是相当明显的.

我对这个问题的目标不是对Xcode或Swift进行批评,而是增加我对编译器如何在Swift中推断类型的了解.

Mar*_*n R 13

如果闭包由单个表达式组成,则仅自动推断闭包的返回类型,例如:

static var jsonURLNL =  { return URL(string: "professionalURL")! }()
Run Code Online (Sandbox Code Playgroud)

或者如果可以从调用上下文推断出类型:

static var jsonURLNL: URL =  {
    if ProcessInfo.processInfo.environment["CONSUMER"] != nil {
        return URL(string: "consumerURL")!
    }
    return URL(string: "professionalURL")!
}()
Run Code Online (Sandbox Code Playgroud)

要么

static var jsonURLNL = {
    if ProcessInfo.processInfo.environment["CONSUMER"] != nil {
        return URL(string: "consumerURL")!
    }
    return URL(string: "professionalURL")!
}() as URL
Run Code Online (Sandbox Code Playgroud)

简化示例:此单表达式闭包编译:

let cl1 = { return 42 }
Run Code Online (Sandbox Code Playgroud)

但是这个多表达式闭包不会:

let cl2 = { print("Hello"); return 42 }
// error: unable to infer complex closure return type; add explicit type to disambiguate
Run Code Online (Sandbox Code Playgroud)

以下行编译,因为类型是从上下文推断出来的:

let cl3 = { print("Hello"); return 42 } as () -> Int

let y1: Int = { print("Hello"); return 42 }()

let y2 = { print("Hello"); return 42 }() as Int
Run Code Online (Sandbox Code Playgroud)

另请参阅此邮件列表讨论中 Jordan Rose的引用:

Swift的类型推断目前是面向语句的,因此没有简单的方法来进行[多语句闭包]推理.这至少部分是编译时间问题:Swift的类型系统允许比Haskell或OCaml更多可能的转换,因此解决整个多语句函数的类型不是一个小问题,可能不是一个易处理的问题.

SR-1570错误报告.

(两个链接和引用都是从flatMap API契约如何将可选输入转换为非可选结果?)复制的.


mat*_*att 7

对匿名函数的返回类型的推断对您来说可能很容易,但事实证明,将其构建到编译器中是非常困难的。

因此,通常不允许在未将类型指定为声明的一部分的情况下编写定义并调用初始值设定项。

但这不是什么大问题。您所要做的就是指定类型!

static var jsonURLNL : URL = ...
Run Code Online (Sandbox Code Playgroud)

(我在头脑中所做的是将类型的包含视为定义和调用初始值设定项的语法的一部分。所以我总是包含它。所以我从来没有遇到过这个错误消息!)


事后思考:考虑以下几点:

static var jsonURLNL =  {
    if ProcessInfo.processInfo.environment["CONSUMER"] != nil {
        return "Howdy"
    }
    return URL(string: "professionalURL")!
}()
Run Code Online (Sandbox Code Playgroud)

你看到问题了吗?现在,即使是人类也无法推断出任何内容,因为您意外地在返回类型中不一致。但是如果你写: URL,现在编译器知道你应该返回什么并且知道这"Howdy"是错误的类型。

  • @CommaToast 如果您认为这很容易,我相信 Apple 有一份工作在等着您。 (2认同)