在 Swift 5 中的泛型方法中展开可选类型
Unwrapping Optional types in a Generic method in Swift 5
我正在尝试从类型 A
的实例创建类型 B
的实例,但是原始类型 A
的一些属性是可选的并且创建如果发生这种情况,B
的应该会抛出错误。
我的问题是我不知道类型 T
是否是可选的,如果是,如何打开它。我正在尝试以下操作,但 swift 无法判断类型应该是什么...
下面的例子很遗憾,真实样本有近百个值。
struct A {
let name: String?
let price: Price?
struct Price {
let value: Double?
}
}
struct B {
let name: String
let priceValue: Double
}
extension A {
func convert() throws -> B {
do {
let name: String = try unwrap(\.name) // error: Type of expression is ambiguous without more context
let priceValue: Double = try unwrap(\.price.value) // error: Type of expression is ambiguous without more context
return B(name: name, priceValue: priceValue)
}
}
func unwrap<U, T>(_ path: KeyPath<A, T>) throws -> U {
let value = self[keyPath: path] // value is of type T
if let value = value as? U {
return value
} else {
throw Error.missing("KeyPath '\(path)' is 'nil'")
}
}
enum Error: Swift.Error {
case missing(String?)
}
}
我知道以下内容会起作用,但我不想在代码中重复这 100 次?
extension A {
func convertWithConditionals() throws -> B {
do {
guard let name = self.name else {
throw Error.missing("KeyPath 'name' is 'nil'")
}
guard let priceValue = self.price?.value else {
throw Error.missing("KeyPath 'price.value' is 'nil'")
}
return B(name: name, priceValue: priceValue)
}
}
}
肯定有一些... swift-y 方法我没有想到。
如果打算调用 unwrap()
仅使用通向可选 属性 的关键路径,那么您可以将参数类型声明为 KeyPath<A, T?>
,第二个占位符类型为 [=不需要 15=]:
func unwrap<T>(_ path: KeyPath<A, T?>) throws -> T {
if let value = self[keyPath: path] {
return value
} else {
throw Error.missing("KeyPath '\(path)' is 'nil'")
}
}
用法可以简化为
func convert() throws -> B {
let name = try unwrap(\.name)
return B(name: name)
}
或者只是
func convert() throws -> B {
return try B(name: unwrap(\.name))
}
我正在尝试从类型 A
的实例创建类型 B
的实例,但是原始类型 A
的一些属性是可选的并且创建如果发生这种情况,B
的应该会抛出错误。
我的问题是我不知道类型 T
是否是可选的,如果是,如何打开它。我正在尝试以下操作,但 swift 无法判断类型应该是什么...
下面的例子很遗憾,真实样本有近百个值。
struct A {
let name: String?
let price: Price?
struct Price {
let value: Double?
}
}
struct B {
let name: String
let priceValue: Double
}
extension A {
func convert() throws -> B {
do {
let name: String = try unwrap(\.name) // error: Type of expression is ambiguous without more context
let priceValue: Double = try unwrap(\.price.value) // error: Type of expression is ambiguous without more context
return B(name: name, priceValue: priceValue)
}
}
func unwrap<U, T>(_ path: KeyPath<A, T>) throws -> U {
let value = self[keyPath: path] // value is of type T
if let value = value as? U {
return value
} else {
throw Error.missing("KeyPath '\(path)' is 'nil'")
}
}
enum Error: Swift.Error {
case missing(String?)
}
}
我知道以下内容会起作用,但我不想在代码中重复这 100 次?
extension A {
func convertWithConditionals() throws -> B {
do {
guard let name = self.name else {
throw Error.missing("KeyPath 'name' is 'nil'")
}
guard let priceValue = self.price?.value else {
throw Error.missing("KeyPath 'price.value' is 'nil'")
}
return B(name: name, priceValue: priceValue)
}
}
}
肯定有一些... swift-y 方法我没有想到。
如果打算调用 unwrap()
仅使用通向可选 属性 的关键路径,那么您可以将参数类型声明为 KeyPath<A, T?>
,第二个占位符类型为 [=不需要 15=]:
func unwrap<T>(_ path: KeyPath<A, T?>) throws -> T {
if let value = self[keyPath: path] {
return value
} else {
throw Error.missing("KeyPath '\(path)' is 'nil'")
}
}
用法可以简化为
func convert() throws -> B {
let name = try unwrap(\.name)
return B(name: name)
}
或者只是
func convert() throws -> B {
return try B(name: unwrap(\.name))
}