我有以下代码,它说明了一个我还没有想好如何干净利落地解决的问题,即:

如何使函数(IsNil)既对nil返回True,又对可选函数(Nil)返回True,而对其他任何内容返回False?

class Foo {
  var baz : Date? = nil
  subscript(key: String) -> Any? {
    get {
      let m = Mirror(reflecting: self)
      for child in m.children {
        if (child.label == key) { return child.value }
      }
      return nil
    }
  }
}

// this works unless the field is an Optional(nil)
func isNil(_ field: Any?) -> Bool {
  if field == nil { return true }
  return false
}

// this sort of works in a really terrible hacked way
func isNilViaString(_ field: Any?) -> Bool {
  if field == nil { return true }
  return "\(field.debugDescription)" == "Optional(nil)"
}

// this returns true as expected
print("isNil(nil) = \(isNil(nil))")
var optionalNil = Foo()["baz"]
// I'd like this to return true as well
print("isNil(optionalNil) = \(isNil(optionalNil))")
// this returns true, but is super hacky
print("isNilViaString(optionalNil) = \(isNilViaString(optionalNil))")
// this is an example of a problem with the isNilViaString method
print("isNilViaString(optionalNil) = \(isNilViaString("Optional(nil)"))")

推荐答案

isNil最好基于展平包含值的可选性.(如果您将isNil直接合并到您的下标中,则可能没有实际用途.)


如果您不关心解包失败的详细信息:

public extension Any? {
  /// Represent an `Optional` with `Any?` instead of `Any`.
  ///
  /// If `any` is an optional, this instance will copy it.
  /// Otherwise, this instance will wrap it.
  ///
  /// - Note: Use this to avoid an `Any?` actually representing an `Any??`.
  init(flattening any: Any) {
    switch any {
    case let optional as Self:
      self = optional
    }
  }

  var isNil: Bool { flatMap(Self.init) == nil }
}
subscript(key: String) -> Any? {
  ( Mirror(reflecting: self).children
    .first { $0.label == key }?
    .value
  ).flatMap(_?.init)
}

如果您这样做了:

public extension Optional {
  /// Represents that an `Optional` was `nil`.
  struct UnwrapError: Error & Equatable {
    public init() { }
  }
}

public extension Any? {
  /// The wrapped value, whether `Wrapped` is an `Optional` or not.
  /// - Throws: `Any?.UnwrapError` when `nil`,
  ///   or  `Any??.UnwrapError` when wrapping another `Optional` that is `nil`.
  var doublyUnwrapped: Wrapped {
    get throws {
      switch self {
      case let doubleWrapped?? as Self?:
        return doubleWrapped
      case _?:
        throw Self?.UnwrapError()
      case nil:
        throw UnwrapError()
      }
    }
  }

  var isNil: Bool { (try? doublyUnwrapped) == nil }
}
subscript(key: String) -> Any {
  get throws {
    try (
      Mirror(reflecting: self).children
        .first { $0.label == key }?
        .value
    )
    .doublyUnwrapped
  }
}

Swift相关问答推荐

自定义完整屏幕封面动画

更改正在进行的异步任务的完成(SWIFT并发)(&q;)?

字符串目录不适用于SWIFT包

它是RxSwift中直接用于可扩展视图的有效的可扩展BehaviorRelay值?

我在SwiftUI中的动画无法正常工作

如何将图像插入到矩形中

SWIFT异步/等待,多个监听程序

如何使用Duration.TimeFormatStyle以h m s格式快速格式化时间

为什么变量不存储在 Swift 的过程数据区中

如何隐藏集合视图中特定的单元格,以避免出现空白空间?

如何从我的 macOS 应用程序打开 (.log) 文件?

Swift // Sprite Kit:类别位掩码限制

在 SwiftUI 中将属性显式设置为其默认值

try 制作一个 Swift 扩展来替换字符串中的多次出现

`let case(value)` 和 `case(let value)` 之间的区别 (Swift)

iOS Swift - 如何更改表格视图的背景 colored颜色 ?

Swift 4 Decodable - 以枚举为键的字典

如何轻松删除领域中的所有对象

在 Swift 中将计时器标签格式化为小时:分钟:秒

Objective-C 方法与可选需求方法 Swift 冲突