2014-09-05 97 views
6

這是對問題的跟進:Protocol func returning Self。該協議如下:Swift協議和全局函數返回類型

protocol Copyable { 
    init(copy: Self) 
    func copy() -> Self 
} 

下工作正常,但copy()功能正是每一個執行相同的,即

func copy() -> Self { 
    return self.dynamicType(copy: self) 
} 

按照這個http://nshipster.com/swift-default-protocol-implementations/我嘗試了全球FUNC

func copy<T : Copyable>(makeCopy: T) -> T { 
    return makeCopy.dynamicType(copy: makeCopy) 
} 

然而,當它在實現以下協議的類中調用時

protocol Mutatable : Copyable { 
    func mutated() -> Self 
} 

class C : Mutatable { 

    var a = 0 

    required init(_ a: Int) { 
     self.a = a 
    } 

    required init(copy: C) { 
     a = copy.a 
    } 

    func mutated() -> Self { 
     let mutated = copy(self) 

     mutated.a++ 

     return mutated // error: 'C' is not convertible to 'Self' 
    } 

} 

我收到錯誤,如上所述。當我輸入mutated自動完成顯示mutated(C),我不知道這意味着什麼。我也嘗試加入requiredfunc mutated(),但顯然required只允許用於inits。任何方式讓這個工作?

回答

1

此問題與複製副本和相同解決方案具有相同的形式。使突變成爲初始化,而不是方法。

protocol Copyable { 
    init(copy: Self) 
} 

protocol Mutatable : Copyable { 
    init(byMutating: Self) 
} 

class C : Mutatable { 
    var a = 0 

    required init(_ a: Int) { 
    self.a = a 
    } 

    required init(copy: C) { 
    a = copy.a 
    } 

    required convenience init(byMutating: C) { 
    self.init(copy: byMutating) 
    self.a++ 
    } 
} 

// These are purely for convenience 
func copy<T : Copyable>(x: T) -> T { 
    return x.dynamicType(copy: x) 
} 

func mutated<T: Mutatable>(x: T) -> T { 
    return x.dynamicType(byMutating: x) 
} 

但重申Mattt的點鏈接的文章中,你可以有一個C(copy: x)語法相當方便,你可以有一個copy(x)語法相當方便,而且總是有x.dynamicType(copy: x)。但是,如果沒有一些煩人的工作,你就不可能有一個x.copy()的語法。您必須在每個類中重複func copy() -> Self { return copy(self) },否則您必須創建一些實現此方法的具體類,並最終從中繼承。這是目前Swift的基本限制。我同意Mattt對可能的解決方案的診斷,並且懷疑某種類型的特徵系統,可能沿着斯卡拉的路線,將來可能會被添加。

Mattt的評論是值得關注的,「所有這些都強調了Swift中方法和函數之間的重大張力。」這是另一種說法,即面向對象範式和功能範式之間存在緊張關係,在它們之間移動可能會造成一些脫節。語言試圖用各種特徵來描述這個問題,但是消息和屬性的對象與數據和組合器的函數之間存在着重要的區別,而「獲取兩全其美」有時會產生一些粗糙的邊緣。

在比較Swift和其他語言時,很容易忘記v0.9和v2.11之間存在很大差異。我們習以爲常的語言理所當然的許多事情在他們的v1中都不存在。


您的意見,您可能會認爲mutatedSelf類型。但是它的類型爲C,正如您的自動完成表明的那樣。如前所述,CSelf不同,除非您可以承諾沒有子類(Cfinal或結構)。除非您使用dynamicType,否則Swift類型將在編譯時解析,而不是運行時解析。

要成爲一個更具體一點,斯威夫特看這條線:

let mutated = copy(self) 

它指出,copy是其參數的類型通用的,它必須在編譯時構建一個版本的copy來電。沒有類型Self。它只是一個佔位符,必須在編譯時解決。在這個詞彙範圍內的self的類型是C。所以它構造了copy<C>。但是,如果你劃分C,這可能是錯誤的功能(在這種情況下,將是)。這與以下密切相關:https://stackoverflow.com/a/25549841/97337

這種類型的自動完成說(C)而不是C事實上的功能和元組如何斯威夫特工作次要的副作用,和漂亮的經常出現,但我還沒有遇到它真正重要的情況下。像func f(x: Int, y:Int)這樣的Swift函數實際上並沒有兩個參數。它有一個類型爲(Int, Int)的2元組參數。這個事實對於curry語法是如何工作是很重要的(關於Swift的更多內容,請參閱Swift編程語言)。所以當你專注於copy時,你可以用(C)這個1元組來專門化它。 (或者,編譯器只是試圖將其作爲各種嘗試中的一種,而這只是它所報告的一種。)在Swift中,任何值都可以簡單地交換爲相同類型的1元組。所以copy的回報實際上是C的1元組,寫成(C)。我懷疑Swift編譯器會隨着時間的推移改進它的消息以消除多餘的括號,但這就是它們有時出現的原因。

+0

好的,所以一切都使用初始化。得到它了。再次感謝! – aeubanks 2014-09-06 16:29:12

+0

我想我的問題是,如果'copy(T) - > T'返回調用它的類,爲什麼原始代碼不工作?在mutated()函數中,它應該返回「Self」,對嗎?即使有更好的方法去做,我仍然很好奇斯威夫特是如何工作的。 – aeubanks 2014-09-06 20:12:42

+0

更新了一些更多的信息 – 2014-09-06 21:00:05