2015-10-07 67 views
1

我有一個泛型類型,我想用不同的方式初始化它,具體取決於實際類型是否爲Optional是否有可能創建一個擴展到一個泛型類型限制爲該類型是可選的,在Swift中?

struct Foo<Bar> { 
    var value: Bar 
} 

extension Foo { 
    init(data: Any) throws { 
     if let typedData: Bar = data as? Bar { 
      self.value = typedData 
     } 
     else { 
      throw NSError(domain: "", code: 0, userInfo: nil) 
     } 
    } 
} 

// (invalid restriction) 
extension Foo where Bar: Optional<Bar> { 
    init(data: Any) throws { 
     if (data as? NSNull) == nil { 
      if let typedData: Bar = data as? Bar { 
       self.value = typedData 
      } 
      else { 
       throw NSError(domain: "", code: 0, userInfo: nil) 
      } 
     } 
     else { 
      self.value = nil 
     } 
    } 
} 

的想法是,我從一些不知名的數據類型的要麼正確初始化,如果該類型對應,否則拋出一個錯誤,但如果NSNull相當於nil值,如果類型爲Optional初始化。

let nonOptionalData: Any = Bar() 
// should be successful 
let foo1: Foo<Bar> = try Foo(data: nonOptionalData) 

let nonOptionalIncorrectData: Any = NSNull() 
// should throw an error 
let foo2: Foo<Bar> = try Foo(data: nonOptionalIncorrectData) 

let optionalData: Any = Bar() 
// should be successful 
let foo3: Foo<Bar?> = try Foo(data: optionalData) 

let optionalIncorrectData: Any = Bob() 
// should throw an error 
let foo4: Foo<Bar?> = try Foo(data: optionalIncorrectData) 

let optionalNullData: Any = NSNull() 
// should be successful 
let foo5: Foo<Bar?> = try Foo(data: optionalNullData) 

有誰知道這是可能的(上面的代碼會失敗,因爲我們不能限制擴展到Optional型),如果是這樣,怎麼可以做什麼?

回答

1

可以按照我已經回答here的相同方式完成。

protocol OptionalType { 
    typealias W 
    static func fromOptional(o: W?) -> Self 
} 

extension Optional: OptionalType { 
    typealias W = Wrapped 
    static func fromOptional(o: W?) -> W? { return o } 
} 

struct Foo<Bar> { 
    var value: Bar 
} 

extension Foo { 
    init(data: Any) throws { 
     if let typedData: Bar = data as? Bar { 
      self.value = typedData 
     } 
     else { 
      throw NSError(domain: "", code: 0, userInfo: nil) 
     } 
    } 
} 

extension Foo where Bar: OptionalType { 
    init(nullableData: Any) throws { 
     if nullableData is NSNull { 
      self.value = .fromOptional(nil) 
     } 
     else if let typedData = nullableData as? Bar.W { 
      self.value = .fromOptional(typedData) 
     } 
     else { 
      throw NSError(domain: "", code: 0, userInfo: nil) 
     } 
    } 
} 

但我一直沒有找到一種方法來使「init(data :)」重載具有相同的簽名,沒有「模棱兩可的使用」錯誤。這就是爲什麼我將後者重載重命名爲「init(nullableData :)」。

let b: Foo<Int?> = try! Foo(nullableData: NSNull()) 
let c: Foo<Int?> = try! Foo(nullableData: 8) 
let a: Foo<Int> = try! Foo(data: 1) 
let d: Foo<Int> = try! Foo(nullableData: 1) // <-- cannot compile 
相關問題