2017-03-01 76 views
2

所以我在写代码来区分我的应用程序的多个版本:为什么Swift编译器不能推断这个闭包的类型?

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

但我得到一个编译器错误:

Unable to infer complex closure return type; add explicit type to disambiguate

为什么不能斯威夫特编译器知道这会返回一个URL ?在这种情况下,我认为这很明显。

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

+0

有关此问题的某些详细信息,请参见[本报告](https://bugs.swift.org/browse/SR-1570)。 – DrummerB

+0

比较http://stackoverflow.com/a/34115788/1187415或http://stackoverflow.com/a/42213785/1187415:仅在“单表达式关闭”时才会自动推断返回类型。 –

回答

2

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

因此,通常不允许编写定义和调用初始化程序,而不指定类型作为声明的一部分。

但这不是一个大问题。你所要做的就是指定类型!

static var jsonURLNL : URL = ... 

(我在我的头做的是治疗型的夹杂物的语法定义和调用初始化的一部分。因此,我总是包含它。所以我从来没有遇到这样的错误消息!)


有感:考虑以下几点:

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

你看这个问题?现在没有什么可以推断,即使是一个人,因为你意外地在你的返回类型中不一致。但是如果你写: URL,现在编译器知道你是假设返回并知道"Howdy"是错误的类型。

+0

问题不在于它是“定义和调用初始化器”。 'static var jsonURLNL = {return URL(string:“professionalURL”)! }()'会编译。 –

+0

@MartinR这是正确的,https://bugs.swift.org/browse/SR-1570明确指出,只有当我们进入多线匿名函数时,编译器才能处理。但是,这似乎太多的信息。正如我在答复中所说的,我只是总是在声明中加入这个类型。我的答案回应了OP的实际使用案例,并描述了我对该用例的看法。 – matt

+0

换句话说,Swift的编译器坏了。只要将机器学习融入其中,很简单。轻松修复! – CommaToast

3

封闭的返回类型是只推断自动如果 闭合由单个表达的,例如:

static var jsonURLNL = { return URL(string: "professionalURL")! }() 

,或者如果类型可以从推断呼叫上下文:

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

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

简化的例子:此单表达闭合编译:

let cl1 = { return 42 } 

但这种多表达闭合不会:

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

以下各行编译,因为类型是从推断背景:

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

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

let y2 = { print("Hello"); return 42 }() as Int 

又见来自约旦玫瑰in this mailing list discussion报价:

Swift's type inference is currently statement-oriented, so there's no easy way to do [multiple-statement closure] inference. This is at least partly a compilation-time concern: Swift's type system allows many more possible conversions than, say, Haskell or OCaml, so solving the types for an entire multi-statement function is not a trivial problem, possibly not a tractable problem.

SR-1570 bug report

(链接和报价均复制自How flatMap API contract transforms Optional input to Non Optional result?)。

+0

但是它可以检查闭包中的所有返回语句,如果它们全部指定了相同的返回类型,那么它只会使用该类型作为闭包的返回类型?还是我简单化了?我真的不知道Swift的类型推断是如何工作的。 – vrwim

+0

@vrwim:我也不知道细节,但这里有一个例子:你可以用不同的返回类型重载函数。在一个像{if condition {return f()} else {return g()}}这样的闭包中,编译器必须弄清楚是否有任何*'f'和* any *'g'具有相同的(或兼容)返回类型。正如我从上面的引用中理解的那样,这不是微不足道的,并且可以使编译过程变慢。 –

相关问题