我有一个泛型类型,我想以不同的方式初始化它,具体取决于实际类型是否为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
类型),如果是这样,它是如何完成的?
答案 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