可选类型
可选类型是个什么东西呢?其实就是把空值与非空值也作为不同的类型来处理。这个空指的是变量值为null,而不是空字符串的空,空数组的空,也不是苍井空的空。
那么变量的类型除了传统的类型之外,还要再说明能不能为空,才构成完整的类型。比如可以为nil的整型变量与不能为nil的整数变量不是一个类型。可以为nil的类型就是可选类型。
如何决定一个变量是否可以为nil呢?用问号,如:var c:Int? ,定义了一个整型变量c,但他是一个可选类型,所以可以为它赋值nil,如:c=nil ,如果没有问号,则c绝不能赋nil值。
要将一个可选类型转成非可选类型,需用惊叹号!如:var d:Int = c ,这是不行滴,需这样:var d:Int = c! 加个惊叹号是为了让程序员明确知道d是个可以为空的家伙,这里的转换需要确保d的值真的不是空的才能保证后面不出现逻辑错误,因为后面再用d的时候,不再判断它是否为空,因为它被认为不可能为空 。如果将d的值赋给c就不用转换了,其原因不用再解释了吧?
由于引入了可选类型,带来了语法书写上的一些变化。比如使用可选类型时,一般是不是先要判断一下它是否为空才使用它的值呢?我们可以这样写:
if c != nil {
print("\(c)*100 = \(c! * 100)")
}
你如果不判断而直接写print这条语句的话,而此时如果c的值却真是空的,那么你再用惊叹号对它进行强制类型转换的话,这就是要让程序驾崩的节奏啊。所以先判断一下才可。
我们还看到输出语句中第一个c不用类型转换,因为那里可以接受nil,而后面的乘法运算就要求c绝不能为空,所以进行了类型转换。
但是有一种更简便一点的写法,如下:
if let x = c {
print("\(x)x100 = \(x*100)")
}
其意思是:如果c不为空时,就把c的值赋给x,然后输出语句直接用x就行了,因为x是一个非空类型。如果c为空,则不赋值给x,当然也不会执行输出语句了。
我们知道 var a:Int
表示a是非可选类型,此时绝不能为a赋nil,而var a:Int?
表示a是可选类型,可以为a赋nil,但还有一种情况,看这种定义变量的方式:
var a:Int!
可以为此变量赋nil,而同时在需要非可选类型的地方可以不用惊叹后对它进行转换。慢,脑子有点乱,这又是什么玩意呢?是这样的,苹果公司发现惊叹号用得太多,过意不去了。因为有的变量就是初始化时用个nil,之后在使用过程中绝对是非空的,但每次都转换太麻烦,于是就提供了这么一种方式。这与传统的不区分空值的类型有什么区别吗?用这种方式定义的变量与传统变量一样,只能你自己保证其值不为空了。
其实用了非可选类型在运行过程中就一定不会变为空了吗?这可难说,还是得自己保证,不过,现在这种区分是否为空的语法倒是时刻能给你提个醒。
错误处理
错误都遵守ErrorType协议,例如:
enum PrinterError: ErrorType {
case OutOfPaper
case NoToner
case OnFire
}
使用 throw 来抛出一个错误,使用 throws 来标记一个函数可以抛出错误。如果你在一个函数内抛出错误,函数立马返回,调用函数的代码可以处理抛出的错误。
func sendToPrinter(printerName:String) throws -> String{
if printerName == "Never Has Toner" {
throw PrinterError.NoToner
}
return "Job sent"
}
有很多方法处理错误。一种方式是使用 do-catch。在 do 代码块中,你在语句的前面用 try 来表明语句能抛出错误。在 catch 块中,可以直接使用 error 来操作错误,你也可以给错误对象指定一个不同的名字。
do {
let printerResponse = try sendToPrinter("Bi Sheng")
print(printerResponse)
} catch {
print(error)
}
将函数sendToPrinter(:) 的参数改成 “Never Has Toner”, sendToPrinter(:) 函数就会抛出错误。
你可以提供多个catch 块来处理不同的错误 。你在 catch 后面可用的语法与switch中的case 后的语法一样。
do {
let printerResponse = try sendToPrinter("Gutenberg")
print(printerResponse)
} catch PrinterError.OnFire {
print("I'll just put this over here,with the rest of the fire.")
} catch let printerError as PrinterError {
print("Printer error: \(printerError).")
} catch {
print(error)
}
另一种处理错误的方式是使用 try? 将结果转成一个可选类型。如果函数抛出一个错误,错误会被忽略,但抛出错误的函数的返回值是nil;如果没抛出错误,函数的返回值是一个包含实际值的可选类型。如:
let printerSuccess = try? sendToPrinter("Mergenthaler")
let printerFailure = try? sendToPrinter("Never Has Toner")