Swift中如何不转字符串判断变量是否为Optional(nil)
实现能识别nil和Optional(nil)的isNil函数
问题场景
我们需要一个isNil函数,对直接的nil和嵌套的Optional(nil)(比如Optional<Optional<Date>>.some(.none)这类外层可选有值、内层为nil的情况)都返回true,对其他任何非空值返回false。现有两种实现都存在缺陷:
- 基础的
isNil函数仅能判断外层是否为nil,无法识别嵌套的Optional(nil); isNilViaString通过字符串匹配实现,不仅实现粗糙,还会出现误判(比如传入字符串"Optional(nil)"也会返回true)。
优雅解决方案
可以通过递归拆解可选值或模式匹配的方式,精准判断嵌套可选的空值情况:
方案1:利用Mirror递归拆解可选值
func isNil(_ value: Any?) -> Bool { guard let value = value else { return true } let mirror = Mirror(reflecting: value) guard mirror.displayStyle == .optional else { // 非可选类型,直接返回false return false } // 可选类型的子节点仅一个,若子节点为nil则整体是Optional(nil) return mirror.children.first?.value == nil }
方案2:模式匹配+递归判断
func isNil(_ value: Any?) -> Bool { switch value { case nil: return true case let optional as Optional<Any>: // 拆解可选值,递归判断内部值是否为空 return isNil(optional.map { $0 }) default: return 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 } } } // 如预期返回true print("isNil(nil) = \(isNil(nil))") var optionalNil = Foo()["baz"] // 现在返回true,符合预期 print("isNil(optionalNil) = \(isNil(optionalNil))") // 传入字符串"Optional(nil)"返回false,避免误判 print("isNil(\"Optional(nil)\") = \(isNil("Optional(nil)"))") // 测试非空可选值 let nonNilOptional: Date? = Date() print("isNil(nonNilOptional) = \(isNil(nonNilOptional))") // 返回false
方案说明
- 两种方案都能正确处理任意层级的嵌套可选值,彻底避免字符串匹配的误判问题;
- 递归逻辑可以覆盖
Optional<Optional<Optional<String>>>.some(.some(.none))这类多层嵌套的空值场景; - 实现逻辑清晰,符合Swift的类型安全特性,比字符串匹配更可靠。
内容的提问来源于stack exchange,提问作者Kem Mason
相关产品推荐
相关产品推荐

