Swift 与 Objective-C

Swift Optional:区分 nil、空字符串与零

用六种输入保留缺失与无效状态,实测nil合并运算符的默认值何时执行,避免把数字0误当成没有输入。

2 分钟阅读
Swift Optional:区分 nil、空字符串与零 封面图

nil、空字符串和数字0是不同状态。把所有可选值都换成默认值,可能抹掉未输入与明确输入0的区别。先决定缺失应该使用正常默认值,还是保留为独立状态。

原理与设计判断

Optional用some与none表示存在与否。局部条件处理选if let,提前返回选guard let,有合理默认值时选??。可选链遇到缺失值会得到nil;强制解包在nil时中止,不适合预期内的输入失败。 一手资料

复现代码

quantity用不同enum表示缺失、无效与有效数量。六个用例是nil、空字符串、cat、-1、0、7。默认值函数记录??调用次数,并单独比较空字符串与缺失字符串的count。

这个独立示例已于 2026-10-23 使用 Apple Swift 6.4,以 Swift 6 语言模式在 arm64 macOS 目标环境运行。不需要网络或额外软件包。

下载完整 Swift 文件

请在下载文件的文件夹中运行。检查不通过时,precondition 会终止程序。请勿使用 -Ounchecked,因为它会移除这些检查。

swift -swift-version 6 swift-optional-enum-unwrapping.swift
enum Quantity: Equatable { case missing, invalid, value(Int) }
func quantity(_ raw: String?) -> Quantity {
    guard let raw else { return .missing }
    guard let value = Int(raw), value >= 0 else { return .invalid }
    return .value(value)
}

let cases: [(String?, Quantity)] = [
    (nil, .missing), ("", .invalid), ("cat", .invalid),
    ("-1", .invalid), ("0", .value(0)), ("7", .value(7))
]
for (raw, expected) in cases { precondition(quantity(raw) == expected) }

var fallbackCalls = 0
@MainActor func fallback() -> Int { fallbackCalls += 1; return 99 }
let present: Int? = 0
let absent: Int? = nil
precondition((present ?? fallback()) == 0 && fallbackCalls == 0)
precondition((absent ?? fallback()) == 99 && fallbackCalls == 1)

let empty: String? = ""
let missing: String? = nil
precondition(empty?.count == 0 && missing?.count == nil)
print("inputs=6 missing=1 invalid=3 valid=2 fallback-calls=1 empty-count=0 missing-count=nil")

运行结果与解读

inputs=6 missing=1 invalid=3 valid=2 fallback-calls=1 empty-count=0 missing-count=nil

结果区分出一个缺失值、三个无效输入和两个有效值。some(0)不执行默认值函数,none才执行一次。空字符串的count是0,缺失字符串的链式访问结果则是nil。类似零的值不代表不存在。

适用范围与限制

这是拒绝负数的数量验证器,不是通用数字输入策略。空白、小数、地区格式和上限都需按需求补充。String!也是会在需要的上下文中隐式解包的可选声明,不是每次使用都无条件强制解包。

接下来要确认的事

先决定缺失与无效输入是否显示不同提示,并与服务器契约一致。如果调用方需要更细的失败原因,请用throws或Result保留信息,而不是默默覆盖成默认值。

延伸实验

来源与验证