2016-09-19 54 views
4

使用我想有一類的靜態初始化方法:「自我」不能在不平凡的封閉

class A { 

    required init() { 
    } 

    // this one works 
    class func f0() -> Self { 
    return self.init() 
    } 

    // this one works as well  
    class func f1() -> Self { 
    let create = { self.init() } // no error, inferred closure type is '() -> Self' 
    return create() 
    } 
} 

不幸的是,斯威夫特3編譯器無法推斷類型,任何停業超過{ self.init() }更復雜。例如:

class func f2() -> Self { 
    let create = { 
    // error: unable to infer complex closure return type; add explicit type to disambiguate 
    let a = self.init() 
    return a 
    } 

    return create() 
} 

任何嘗試來指定閉合類型,變量的類型顯式或從ASelf到引線投射到一個錯誤:

class func f3() -> Self { 
    let create = {() -> Self in // error: 'Self' is only available in a protocol or as the result of a method in a class; 
    let a = self.init() 
    return a 
    } 

    return create() 
} 

class func f4() -> Self { 
    let create = { 
    let a: Self = self.init() // error: 'Self' is only available in a protocol or as the result of a method in a class; 
    return a 
    } 

    return create() 
} 

class func f5() -> Self { 
    let create = {() -> A in 
    let a = self.init() 
    return a 
    } 

    return create() as! Self // error: cannot convert return expression of type 'A' to return type 'Self' 
} 

解決方法是避免使用封閉Self

這似乎是編譯器的一個非常不幸的限制。背後有理由嗎?這個問題可能在未來的Swift版本中得到解決嗎?

+1

雖然不完全相同,但它與http://stackoverflow.com/questions/25645090非常相似/協議FUNC-返回自。根本問題是Swift需要在編譯時確定'Self'的類型,但是你想在運行時確定它。它已經有所擴展,允許類函數運行Self,如果一切都可以在編譯時解決,但Swift不能總是證明你的類型*在某些情況下必須是正確的(有時是因爲它不知道如何但是,有時是因爲它實際上可能是錯的)。 –

+0

我期望這會變得更好一些,但Swift不鼓勵這種複雜的繼承(這些是非最終類,所以你必須考慮所有可能的子類)並且更喜歡長期的協議,所以我不希望這樣做完全有可能在Swift 4或5. –

+0

@RobNapier _Swift不能總是證明你的類型在某些情況下必須是正確的(有時是因爲它現在還不知道如何,有時候因爲它實際上可能是錯的) 。是否有這種情況的例子? –

回答

2

根本問題是Swift需要在編譯時確定Self的類型,但是您希望在運行時確定它。它已經有所擴展,允許類函數返回Self,如果一切都可以在編譯時解決的話,但Swift不能總是證明你的類型在某些情況下必須是正確的(有時候因爲它還不知道如何,有時是因爲它實際上可能是錯的)。

作爲一個例子,考慮一個不覆蓋自迴歸方法的子類。它如何返回子類?如果它將Self傳遞給別的什麼呢?你怎麼能靜態類型檢查,在編譯時將來的子類編譯器甚至不知道? (包括可以在運行時和模塊邊界添加的子類)

我期望這會稍微好一點,但Swift不鼓勵這種複雜的繼承(這些是非最終類,因此您必須考慮所有可能的子類)並且更喜歡長期協議,所以我不認爲這在Swift 4或5中是完全可能的。