2016-02-26 72 views
2

由於Swift Language Guide指出泛型類型可以是制約類或協議是這樣的:如何創建一個約束於結構的泛型類?

public class MyGenericClass<T:Equatable> { 
    func printEquality(a:T, b:T) { 
     if a == b { 
      print("equal") 
     } else { 
      print("not equal") 
     } 
    } 
} 

我可以以某種方式限制T是一個struct

我的用例是值類型的觀察者類,它只應被結構體使用。

附註:我知道有例如只有類的協議,只能通過類來實現。這並沒有真正相關,但表明有時候有一種特殊的方式來實現目標。

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol { 
    // class-only protocol definition goes here 
} 
+0

繼承僅與類(引用類型)相關。 SomeInheritedProtocol在Swift中沒有意義。與協議相關的是一致性。但運行時檢查某些類型的實例是否符合AnyObject協議是否可用使用is運算符 – user3441734

+0

密切相關:http://stackoverflow.com/questions/33623104/how-to-restrict-a-protocol-to-value-types -only: –

+0

@ user3441734該代碼片段是Swift語言指南中「協議」一章的引用。 – Klaas

回答

2

你不能(從Swift 2.2開始)。

這根本不可能。沒有struct版本的AnyObject,即AnyValue協議(對所有值類型自動實施)。

我自己也遇到過這個確切的問題,我很抱歉地說,除了嚴格遵守非正式協議外,沒有其他解決方案。希望Swift 3能解決這個問題。

1

另一個答案很好地回答了這個問題(即:你不能(還?))。

我想我會補充說,你可以,但是,至少模仿這種使用運行時反思和failable初始值設定項的行爲;這樣只有在T是一個結構(符合Equatable)時,才能成功初始化通用類。

public class MyGenericClass<T: Equatable> { 
    var foo: T 

    init?(bar: T) { 
     foo = bar 

     if Mirror(reflecting: foo).displayStyle != .Struct { 
      return nil 
     } 
    } 
} 

struct Foo : Equatable { 
    let foo = 1 
} 
func ==(lhs: Foo, rhs: Foo) -> Bool { return lhs.foo == rhs.foo } 

/* Example */ 
if let _ = MyGenericClass<Int>(bar: 1) { 
    print("Integer") 
} 
if let _ = MyGenericClass<Foo>(bar: Foo()) { 
    print("Foo-Struct") 
} 
// prints only "Foo-Struct" 

你可以解釋初始化失敗作爲通用T的不符合「只允許T是結構」,並可能使用另購的結合(/ ...)與您的觀察器類使用在實踐中。

+0

在Swift中Int實際上是struct,Double實際上是struct等等。你可以用AnyObject檢查符合AnyObject(和不符合)如果bar是AnyObject {// bar是引用類型,class} else {// bar是值類型struct }不要混合type和displayStyle !!! – user3441734

+0

@ user3441734我將OP的問題解釋爲關於在明確的結構類型(不是原生類型,本質上,在引擎後面,結構體)意義上將協議約束爲「結構體」。對原生值類型的反思將爲'.displayStyle'返回'nil',因此在上例中只允許使用「純粹結構」。如果OP要求_「僅限於一個通用值類型」(特別是沒有提及結構),那麼AnyObject解決方案是一個很好的選擇。然而,當我解釋這個問題時,這就要求涵蓋所有的值類型(包括本地值)。 – dfri

+0

@dfri感謝您的解決方案。我也在考慮類似的事情。 – Klaas