2017-03-01 38 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'具有相同的(或兼容)返回類型。正如我從上面的引用中理解的那樣,這不是微不足道的,並且可以使編譯過程變慢。 –

相關問題