2

我正在尝试B从 type 的实例创建 type 的实例A,但是原始类型的某些属性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)
    }
  }
}

一定有一些......我没有想到的快速的方式来做到这一点。

4

1 回答 1

3

如果打算unwrap()仅使用通向可选属性的关键路径进行调用,则可以将参数类型声明为,并且不需要KeyPath<A, T?>第二个占位符类型:U

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))
}
于 2021-01-07T20:02:32.093 回答