2016-12-07 76 views
6

一個協議,我想用一個通用的類型化類和類型約束:超過一個類型約束

class MyCustomClass<T : Equatable> { 
    var a: Array<T> 
    init() { 
    a = Array<T>() 
    } 
} 

這工作正常。但是如果我想使用第二個協議f.e.會發生什麼?

class MyCustomClass<T : Equatable, IndexableBase> { 
    var a: Array<T> 
    init() { 
    a = Array<T>() 
    } 
} 

它說,初始值設定項失敗,因爲我必須使用2而不是1參數。我不明白。

回答

1

您可以使用此解決方案

class MyCustomClass<T: Equatable where T: IndexableBase > { 
    var a: Array<T> 
    init() { 
     a = Array<T>() 
    } 
} 
+0

Where運算符適合我(Xcode 8.1,Swift 3),所以我使用這個解決方案。 – altralaser

+2

@altralaser即使這個在你的Swift 3中「起作用」,它應該給你一個警告,即[** emphasis ** mine]:_「warning:'where''子句旁邊的通用參數**已被棄用並且將在未來版本的Swift **「_」中被刪除。因此,您可能希望使用Swift 3的最新解決方案,否則您的實現將在Swift的未來更新中被破解(請參閱Swift 3最新版本的其他兩個答案)。 – dfri

14

斯威夫特3

(我已經在你的榜樣取代IndexableBaseCollection,你應該更喜歡後者)


按照Swift 3,協議組合使用infix ope rator &protocol<...>構建體,如在接受和執行進化提案描述:

因此,使用協議的組合物也可放置組合式約束在該參數的T佔位符清單:

class MyCustomClass<T: Equatable & Collection> { /* ... */ } 

作爲協議組合的替代方案,您還可以使用where子句來加入多個類型(和子類型)約束。按接受和實施發展建議:

where條款已被轉移到聲明的結束,在這種情況下,你的例子將是:

class MyCustomClass<T: Equatable> where T: Comparable { /* ... */ } 

或,甚至將完整的協議組合與where子句放在聲明末尾

class MyCustomClass<T> where T: Equatable & Comparable { /* ... */ } 

我們應該喜歡什麼風格?

有趣的討論是我們應該考慮的「最佳實踐」,因爲這個特定的主題沒有指定Swift API指南。難道我們把

  • 所有(主要類型)約束的參數列表,或
  • 在聲明的末尾的所有限制,或
  • 分手約束與一些參數列表和其他人置於宣言結束?

考慮以下人爲的例子,其中我們有一個構建體,我們打算作爲一種類型的約束(Doable),這本身持有associatedtype這是我們可以將一種類型的約束使用的協議。

protocol Doable { 
    associatedtype U 
} 

使用上面的方法不同,下面所有的三種方法是有效的,語法

// alternative #1 
func foo<T: Equatable & Doable>(_ bar: T) ->() where T.U: Comparable { /* ... */ } 

// alternative #2 
func foo<T: Equatable>(_ bar: T) ->() where T: Doable, T.U: Comparable { /* ... */ } 

// alternative #3 
func foo<T>(_ bar: T) ->() where T: Equatable & Doable, T.U: Comparable { /* ... */ } 

我會從the evolution thread that that brought forth SE-0081引述蘋果開發喬格勒夫:

這是一個主觀判斷。這是我的感覺是,在很多情況下,一個通用的 參數是由至少一個重要的協議或基地 類是值得呼叫前面,所以這是合理的,允許像

func foo<C: Collection>(x: C) -> C.Element 

萬物而不放逐Collection約束這個限制距離聲明的前面 太遠了。

因此在上面的人爲的例子,它可能是適當的在參數列表中使用的協議的組合物爲直接適用於通用的佔位符T類型的限制,並把這些約束,而的T.U亞型約束是放置在聲明的最後。即,上面的替代方案#1。

+0

這令人印象深刻!但是你對[這個建議]有什麼看法(https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md)?我回答的基礎上... btw我不是downvoter,我是upvoter :) –

+0

@AhmadF謝謝。這個建議也包含在我的答案中,我相信它和新的協議組合(同一概念的兩個部分)是一樣的。有趣的討論是我們應該考慮的最佳實踐,因爲它在Swift API指南中沒有詳細說明。我們是否將所有約束放在聲明的末尾,還是僅限於子類型約束?有一個有趣的討論與SE-0081的演化提案有關,其中包含一些想法以及在哪裏放置不同約束的優缺點;在我的回答中,我將包括一點這個討論。 – dfri

+0

說實話我發現是「冷卻器」,我不知道它存在! –