一、哨崗值
int ch;
while ((ch = getchar()) != EOF) {
printf("Read character %c\n", ch);
}
printf("Reached end-of-file\n");
像上面的EOF,這種東西被叫做哨崗值,其廣泛存在與c、C++、java之中。其存在有其合理性,但是卻很不合理,其混淆了正常值、需要一些潛規則知識等等,不合理因素。
Tony Hoare 在 1965 年設計了 null 引用,他對此設計表示痛心疾首,並將這個問題稱爲 “價值 十億美元的錯誤”。
二、通過枚舉解決魔法數的問題
上文中的哨崗值其實就是一個魔法數,大家都知道這是不好的。所以在Swift中,引入了可選值(通過枚舉、關聯值、泛型來實現)。
// 可選值的核心代碼
enum Optional<Wrapped> {
case none
case some(Wrapped)
}
// 由於可選值遵循了ExpressibleByNilLiteral協議,所以可是用nil來代替none
三、可選值概覽
var array = ["one", "two", "three", "four"]
// 檢查可選值是否爲 nil,如果不是 nil,便會解包可選值
// idx 的類型就是 Int (而不再是可 選值),並且 idx 也只在這個 if let 語句的作用域中有效
if let idx = array.firstIndex(of: "four") {
array.remove(at: idx)
}
// while let 語句和 if let 非常相似,它表示當一個條件返回 nil 時便終止循環。
while let line = readLine() {
print(line)
}
// 爲了解決if、while、switch解包後值的作用域問題,引入了guard語句
// 可選鏈
// ?? 運算符
// 在字符串插值中使用可選值
let bodyTemperature: Double? = 37.0
let bloodGlucose: Double? = nil
print(bodyTemperature) // Optional(37.0)
// 警告:表達式被隱式強制從 'Double?' 轉換爲 Any
print("Blood glucose level: \(bloodGlucose)") // Blood glucose level: nil // 警告:字符串插值將使用調試時的可選值描述,
// 請確認這確實是你想要做的。
infix operator ???: NilCoalescingPrecedence
public func ???<T>(optional: T?, defaultValue: @autoclosure () -> String) -> String
{
switch optional {
case let value?: return String(describing: value)
case nil: return defaultValue()
}
}
print("Body temperature: \(bodyTemperature ??? "n/a")") // Body temperature: 37.0
print("Blood glucose level: \(bloodGlucose ??? "n/a")")
// Blood glucose level: n/a
可選值提供了map、flatMap、compactMap方法。
四、強制解包的時機
當你能確定你的某個值不可能是 nil 時可以使用歎號,你應當會希望如果它意外是 nil 的話,程序應當直接掛掉。
// 提供!!運算符,用於強制解包時,能夠輸出友好的信息
infix operator !!
func !! <T>(wrapped: T?, failureText: @autoclosure () -> String) -> T { ifletx=wrapped{returnx}
fatalError(failureText())
}
let s = "foo"
let i = Int(s) !! "Expecting integer, got \"\(s)\""
五、隱式解包可選值
強制解包會引發崩潰,但是隱式解包與強制解包類似,但是它依然存在。
- 在使用從nib獲取的outlet時,此時一般使用隱式解包
- 爲了與OC代碼兼容