Swift4 基础之 可选类型、可选绑定、隐式解析可选


/*
 可选类型
 要么有值,值等于x;要么没有值,即为 nil。
 */

let possubleNumber = "123"
let convertedNumber = Int(possubleNumber)
/*
 convertedNumber 的类型为 Int? 即为 "optional Int"。
 暗示该值可能是 Int,或者不是Int,即为 nil。
 */

print(convertedNumber)
/*
 输出:
 Optional(123)
 */

let possubleNumber2 = "Hello World"
let convertedNumber2 = Int(possubleNumber2)
print(convertedNumber2)
/*
 输出:
 nil
 */

/*
 nil
 表示值缺失,不能用于非可选的常量和变量。
 在 Objective-C 中,nil 是一个指向不存在对象的指针。
 在 Swift 中,nil 不是指针——它是一个确定的值,用来表示值缺失。
 
 var serverResponseCode: Int = 404
 serverResponseCode = nil
 
 上面的代码会报错!
 
 var serverResponseCode: Int? = 404
 serverResponseCode = nil
 
 这样的代码就不会报错了。
 
 如果代码中有常量或者变量需要处理值缺失的情况,
 请把它们声明成对应的可选类型。
 */

/*
 声明一个可选常量或者变量但是没有赋值,它们会自动被设置为 nil:
 */

var surveyAnswer: String?
/*
 surveyAnswer 的值默认为 nil
 */

/*
 可以使用 if 语句和 nil 比较来判断一个可选值是否包含值。
 可以使用“相等”(==)或“不等”(!=)来执行比较。
 */

if convertedNumber != nil {
    print("convertedNumber 不等于 nil")
}

/*
 确定可选类型确实包含值之后,
 可以在可选的名字后面加一个感叹号(!)来获取值。
 这个惊叹号表示“我知道这个可选有值,请使用它。”
 这被称为可选值的强制解析(forced unwrapping)。
 */

if convertedNumber != nil {
    print("convertedNumber 的值为 \(convertedNumber!)")
}

/*
 使用 ! 来获取一个不存在的可选值会导致运行时错误。
 使用 ! 来强制解析值之前,一定要确定可选包含一个非  nil 的值。
 */

/*
 可选绑定
 用来判断可选类型是否包含值,
 如果包含就把值赋给一个临时常量或者变量。
 
 可以用在 if 和 while 语句中,
 这条语句不仅可以用来判断可选类型中是否有值,
 同时可以将可选类型中的值赋给一个常量或者变量。
 */

if let constantNumber = convertedNumber {
    print("constantNumber 的值为 \(constantNumber)")
}

/*
 用可选绑定来重写 possibleNumber 这个例子:
 */

if let actualNumber = Int(possubleNumber) {
    print("\'\(possubleNumber)\' has an integer value of \(actualNumber)")
} else {
    print("\'\(possubleNumber)\' could not be converted to an integer")
}


/*
 可以包含多个可选绑定或多个布尔条件在一个 if 语句中,
 只要使用逗号分开就行。
 
 只要有任意一个可选绑定的值为nil,
 或者任意一个布尔条件为false,
 则整个if条件判断为false,
 这时你就需要使用嵌套 if 条件语句来处理,
 如下所示:
 */

if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
    print("\(firstNumber) < \(secondNumber) < 100")
}


if let firstNumber = Int("4") {
    if let secondNumber = Int("42") {
        if firstNumber < secondNumber && secondNumber < 100 {
            print("\(firstNumber) < \(secondNumber) < 100")
        }
    }
}

/*
 注意:
 在 if 条件语句中使用常量和变量来创建一个可选绑定
 ,仅在 if 语句的句中(body)中才能获取到值。
 相反,在 guard 语句中使用常量和变量来创建一个可选绑定,
 仅在 guard 语句外且在语句后才能获取到值,请参考提前退出。
 */


/*
 提前退出
 条件为真,才会执行guard语句后的代码。
 条件为假,会执行else从句中的代码。
 guard,总会带有else 语句。
 */

func greet(person: [String: String]) {
    guard let name = person["name"] else {
        return
    }
    print("Hello \(name)")
    
    guard let location = person["location"] else {
        print("I hope the weather is nice near you.")
        return
    }
    
    print("I hope the weather is nice in \(location)")
}

greet(person: ["name": "John"])
greet(person: ["name": "Hane", "location": "Cupertion"])


/*
 隐式解析可选类型
 其实就是一个普通的可选类型,
 但是可以被当做非可选类型来使用,
 并不需要每次都使用解析来获取可选值。
 */

/*
 可选类型String
 */
let possibleString: String? = "An optional string."
/*
 需要感叹号来获取值
 */
let forcedString: String = possibleString!


/*
 隐式解析可选类型String
 */
let assumedString: String? = "An implicitly unwrapped optional string."
/*
 需要感叹号来获取值
 */
let implicitString: String = assumedString

/*
 注意:
 如果在隐式解析可选类型没有值的时候尝试取值,
 会触发运行时错误。
 */


/*
 可以把隐式解析可选类型当做普通可选类型来判断它是否包含值
 */
if assumedString != nil {
    print(assumedString)
}

/*
 也可以在可选绑定中使用隐式解析可选类型来检查并解析它的值
 */
if let definiteString = assumedString {
    print(definiteString)
}

/*
 注意
 如果一个变量之后可能变成nil的话请不要使用隐式解析可选类型。
 如果你需要在变量的生命周期中判断是否是nil的话,请使用普通可选类型。
 */