Swift中的可选类型(Optional Type)

Optional Type总览

什么是optional?
Swift中声明的一个变量时, 默认情况下它是non-optional的, 即必须赋予这个变量一个非空的值. 如果给non-optional类型的变量赋值nil, 编译器就会报错。

var string1: String = "This is string1" // OK
string1 = nil  // Nil cannot be assigned to type 'String'
- Swift中, 当声明一个类的属性时, 属性默认也是non-optional的
swift
class MyClass {
    var name: String = "Lv"
    var age: String  // Class 'MyClass' has no initializers
}

对于之前使用Objective-C的同学来说, 这样的错误可能会让你们有些惊讶, 因为在Objective-C中, 当把nil赋值给一个变量或者声明一个没有初始值的属性时, 编译器都不会报错.

NSString *string1 = @"This is string1";
string1 = nil;
class MyClass {
    NSString *name = @"Lv"
    NSString *age;
}

然而并不意味着在Swift中不能声明一个没有初始值的属性. Swift中引入了可选类型(optional type)来解决这一问题. 它的定义是通过在类型生命后加加一个?操作符完成的.

class MyClass {
    var name: String?  // OK
    var age: String?  // OK
}

为什么引入可选类型?

Swift是一门安全的编程语言. 正如苹果所言, 可选类型就是证明Swift是一门安全的编程语言的一个小例子. 如上面的例子所示, Swift的可选类型提供了在编译阶段就检查一些可能在运行时才会出现的常见错误的机制. 下面通过下面的例子更好的诠释一下可选类型的威力.

- (NSString *)findStockCode:(NSString *)company {
    if ([company isEqualToString:@"Apple"]) {
        return @"AAPL";
    } else if ([company isEqualToString:@"Google"]) {
        return @"GOOG";
    }
    return nil;
}

  • 通过findStockCode:方法可以传入公司的名字,然后得到对应公司的股票代码. 为了方便演示, 这里只返回Apple和Google的代码, 对于其他的传入参数, 统统返回nil.

  • 假设在同一个类中调用findStockCode:方法:

NSString *stockCode = [self findStockCode:@"Facebook"]; // nil is returned
NSString *text = @"Stock Code - ";
NSString *message = [text stringByAppendingString:stockCode]; // runtime error
NSLog(@"%@", message);

上面的代码是可以编译通过的, 但是因为传入了"Facebook"导致返回值是nil, 当代码开始运行后, 程序就会报错了.

当使用Swift中的可选类型时, 上面在运行时才会出现的错误在编译阶段就会报错. 如果使用Swift的代码重写上面的例子,代码如下:

func findStockCode(company: String) -> String? {
   if (company == "Apple") {
      return "AAPL"
   } else if (company == "Google") {
      return "GOOG"
   }
   return nil
}
var stockCode:String? = findStockCode("Facebook")
let text = "Stock Code - "
let message = text + stockCode  // compile-time error
print(message)
  • stockCode被定义成可选类型. 这就意味着它要么是一个String, 要么就是nil. 因为编译器在编译阶段就检测到了潜在的错误(可选类型的值没有被解包: value of optional type String? is not unwrapped)并且提示你去改正, 这段代码就不能够被执行.

  • 从这个例子中可以看到, Swift的可选类型加强了对空值的检查, 并且在编译阶段就给开发者提供了可能的错误信息. 很明显, 可选类型的引入可以让代码的质量变得更好.

解包可选类型(Unwrapping Optionals)

如何让上面的代码正常运行? 很明显, 这里需要判断stockCode是否为空. 代码如下:

var stockCode:String? = findStockCode("Facebook")
let text = "Stock Code - "
if stockCode {
    let message = text + stockCode!
    print(message)
}

像在Objective-C中一样, 还是使用if来判断stockCode中是否有值. 一旦确定stockCode中肯定有值时, 将一个感叹号(!)加在可选类型变量名后面来解包这个可选类型的变量. 在Swift中, 这叫做硬解包. 即直接在可选类型后面加一个感叹号来表示它肯定有值.

上面的例子中, 我们只是自己知道stockCode肯定有值, 所以才直接硬解包了stockCode变量. 但是万一有时候我们的感觉是错的, 那程序在运行时可能会出现严重的错误. 所以Swift中是推荐先检查可选类型是否有值, 然后再进行解包的!

var stockCode:String? = findStockCode("Facebook")
let text = "Stock Code - "
let message = text + stockCode!  // runtime error

以上代码在编译阶段不会报错.因为使用了硬解包, 编译器认为可选类型是有值的, 所以编译是通过的. 当代码运行起来时, 知名的错误将会出现: fatal error: Can’t unwrap Optional.None

可选绑定(Optional Binding)
  • 与硬解包不同, 可选绑定(Optional Binding)是一种更简单更推荐的方法来解包一个可选类型. 使用可选绑定来检查可选类型的变量有值还是没值. 如果有值, 解包它并且将值传递给一个常量或者变量.

  • 再多的言语描述也不如直接上代码来的实际! 将上面的代码改成可选绑定的代码如下:

var stockCode:String? = findStockCode("Facebook")
let text = "Stock Code - "
if let tempStockCode = stockCode {
    let message = text + tempStockCode
    print(message)
}
if let或者if var是可选绑定的两个关键字.

使用自然语言来描述上面这段代码的话, 意思就是如果stockCode有值,解包它,并且将它的值赋值给tempStockCode, 然后执行下面的条件语句; 如果stockCode为空, 直接跳过条件语句块.

以上代码可以简化如下:

let text = "Stock Code - "
if var stockCode = findStockCode("Apple") {
    let message = text + stockCode
    print(message)
}
  • 这里stockCode不再是可选类型, 所以不需要使用!来解包. 如果findStockCode:方法返回值是nil, 那么程序并不会执行条件语句块中的代码.

转载地址:
http://www.cocoachina.com/swift/20160810/17330.html?utm_source=tuicool&utm_medium=referral

你可能感兴趣的:(Swift中的可选类型(Optional Type))