【问题标题】:Unwrapping Optional types in a Generic method in Swift 5在 Swift 5 的通用方法中展开可选类型
【发布时间】:2021-01-07 19:32:02
【问题描述】:

我正在尝试从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 generics optional swift-keypath


    【解决方案1】:

    如果打算仅使用通向可选属性的键路径调用unwrap(),则可以将参数类型声明为KeyPath&lt;A, T?&gt;,并且不需要第二个占位符类型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))
    }
    

    【讨论】:

    • 当我使用你的方法时,如果 keyPath 深度超过 1 层,我仍然会收到 Type of expression is ambiguous without more context 错误
    • @StephenFurlani:所以你有例如一个有 2 层的 keypath,其中 both 是可选的?试试这个:let name = try unwrap(\.firstLayer?.name) 在第一层属性后面加上问号。
    • 漂亮!谢谢!我知道一定有什么华丽的、快速的方法。
    • @MartinR svg uiimageview 的图像位置...我们想要获取 UIImageview 内部图像的 x,y 位置。 Imageview 在主屏幕上为 0.3%,前导、尾随、底部为 0,内容模式为 aspectfit。现在我想在图像内动态添加标签。如何计算这个原点图像只给出宽度和高度
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-12
    • 1970-01-01
    相关资源
    最近更新 更多