在Swift中,是否可以创建一个限制为该类型是可选类型的泛型类型的扩展?

时间:2015-10-07 09:19:57

标签: swift generics optional

我有一个泛型类型,我想以不同的方式初始化它,具体取决于实际类型是否为Optional

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 个答案:

答案 0 :(得分: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
相关问题