Swift可选
Swift Optional是Swift编程中非常重要的基础概念。
可选是在Swift开发中要处理的很多事情。
让我们看看它为我们提供了什么。
如果您不了解Swift的基础知识,则可以在继续之前轻而易举地阅读本文。
需要Swift可选
通常,在Swift中,我们将变量或者常量定义为:
var str = "String type inferred" var string:String = "Type defined" let const = "I'm a constant. I can't change" let i:Int = 0
注意:常数一经定义就无法更改。
在我们尝试将其设置如下之前,使用上面的声明就很好了。
string = nil //Compile Time Error: error: nil cannot be assigned to type 'String' var currentValue:String = nil //Error
上面的代码片段显示Swift变量,常量始终需要一个值。
不设置任何值将导致编译时错误。
这就是Swift为我们提供Optional(一项非常强大的功能)的地方。
在可能缺少值的情况下(例如,在上述代码段中存储nil值),我们可以使用optional。
Swift可选
Swift可选变量或者常量可以包含值或者nil值。
可选的变量/常量声明在类型之后需要一个"?"。
下面给出了可选变量/常量的声明。
var currentValue:Int? = nil var x :String? = "Optional variable" print(currentValue) //prints nil print(x) //prints Optional("Optional variable") currentValue = 1 x = nil print(currentValue)//prints Optional(1) print(x) //prints nil
Swift Optionals就像普通类型一样。
可选类型充当普通类型的包装,具有添加的功能,以允许变量/常量为零。
因此,打印一个可选值将把值包装在Optional()
中。
任何可选类型" Int?"或者" String"与" Int"或者" String"都不相同。
因此,可选类型不能与普通类型进行交互。
可选类型不能与另一个可选类型进行交互,如下图所示。
要使用Optional类型的值,我们需要使用!
将其解包。
这就是XCode的建议。
但是理想吗?我们很快就会看到所有这些。
Swift可选展开
Swift可选变量解包用于将可选类型转换为普通类型(从Int?到Int)。
展开有两种类型:
强制展开Swift可选变量
这是XCode通过在可选变量的末尾添加一个"!"来建议(检查上一张图像)的含义。
下面给出一个例子。
var a:Int? = 2 var c:Int? = 3 var b:Int = 4 print(a!) //prints 2 print(a! + b) //prints 6 print(a! + c!) //prints 5 var unwrapThis:String? = "Unwrap me please" print(unwrapThis) //prints Optional("Unwrap me please") print(unwrapThis!)//prints Unwrap me please
在向每个可选变量/常量添加!
时,它可能会变得非常多余。
我们可以定义一个可选变量,该变量在调用时会隐式解包,如下所示。
var a:Int! = 2 var c:Int! = 3 var b:Int = 4 print(a) //prints 2 print(a + b) //prints 6 print(a + c) //prints 5
类型后带有!
而不是?
的变量称为隐式解包可选。
每当调用它时,它就可以与普通变量进行交互,因为它将隐式地展开为普通类型。
众所周知,但是当变量/常量为nil时定义这种方式可能会很冒险(由于普通类型不能具有nil值,因此会导致崩溃)。
值得注意的是,Force Unwrapping告诉Swift编译器您确定变量不会为nil。
并非总是如此。
这是救援的第二种类型。
Swift可选变量的可选展开
其中我们有条件地检查可选变量是否具有nil值。
只有在没有的情况下,我们才会对其进行包装。
展开可选内容的一种方法是在强制展开之前检查该值是否为nil,如下所示。
if name != nil { if desc != nil { print(name! + ": " + desc!) //prints Swift Tutorial: Optionals } else{ print(name! + ": Undefined") } } else{ print("Nothing is defined") }
在上述方法中,只有在确定值不为零时,我们才会进行包装。
注意:Swift编译器对白色间距敏感。
下面给出了使用三元运算符的可选展开。
var i:Int? = nil let ternary = i != nil ? i! : -1 print("Value of i is \(ternary)") //prints -1
Swift甚至提供了一种巧妙的方法来解开可选项。
让我们在下一部分中看到它。
Swift可选绑定
Swift Optional Binding用于查找可选项是否包含值。
如果确实如此,则将该值用作临时常量或者变量。
所有这一切都在一个动作中完成。
下面给出一个例子。
var desc: String? = "Optionals" if let temp = desc{ print(temp) } else{ print("No description") }
在上面的代码中,如果desc
内的值不是nil,我们将其保存在临时变量或者常量中并使用它。
建议使用可选绑定解开可选组件。
下面给出了一个使用多个if let的示例。
var first:String? = "first" var second:String? = "second" var third:String? = "third" if let f = first { if let s = second{ if let t = third{ print(f + " " + s + " " + t ) } else{ print(f + " " + s + " NA") } } else{ print(f + " NA") } } else{ print("NA") }
现在,它具有太多的嵌套,将需要太多的if-let检查,以便每个范围中都可以使用临时变量。
当然,我们可以改善它。
有一种超短格式,可以进行可选的绑定" if-let",如下所示。
var first:String? = "first" var second:String? = nil let f = first ?? "NA" print(f) //prints first let s = second ?? "NA" print(s) //prints NA
??
解开包装并将可选值存储在变量/常量中。
如果可选值为" nil",则使用右侧的默认值。
以上概念可以应用于之前显示的嵌套" if let"代码。
var first:String? = "first" var second:String? = nil var third:String? = "third" print ("\(first ?? "NA")" + " \(second ?? "NA")" + " \(third ?? "NA")") //prints first NA third
单条语句中的多个可选绑定
我们可以在单个if语句中用逗号分隔多个可选选项,如下所示:
var optionalX :String? = "x" var optionalY :String? = "y" if let x = optionalX, let y = optionalY { print(x) //prints "x" print(y) //prints"y" } else{ print("One or more Optional can't be unwrapped") }
但是,上述方法存在一个陷阱。
如果无法解开任何可选选项,则它们不能在if语句中使用,如下所示:
var optionalX :String? = "x" var optionalY :String? = "y" var optionalZ :String? if let x = optionalX, let y = optionalY, let z = optionalZ { print(x) print(y) print(z) } else{ print("One or more Optional can't be unwrapped") //this gets printed. x and y are skipped too. }
因此,仅当您需要所有可选值中的任何一个或者不需要所有可选值时,才建议使用上述方法。
Swift guard
guard是Swift的另一个强大功能,可用于代替嵌套的if。
guard与if条件类似,只是警卫只检查所有不良情况。
保护声明的结构形式为:
func functionName() { guard <condition> else{ //break or return since the condition has failed } //Do something since your condition has passed the bad checks. }
guard在某种程度上是一种颠倒的条件。
此外,guard仅在功能内部起作用。
下面给出了一个防护示例。
func exampleGuard() { var didWeMeet = false guard !didWeMeet else { return } print("Did we meet? " + String(didWeMeet)) } exampleGuard() //prints "Did we meet? false\n" //Example 2 func exampleGuard2() { var didWeMeet = false guard didWeMeet else { return } print("Did we meet? " + String(didWeMeet)) } exampleGuard2() //else statement executed and function returns void
在上面的代码中,如果在guard关键字之后输入的条件失败,则该函数将执行else情况并返回。
下面给出了带有可选绑定的后卫示例:
var second:String? = nil func guardStatements() { guard let sa = second else{ print("nil value") return } print(sa) } guardStatements() //prints nil value
在上面的代码中,由于second的可选值是nil,所以将运行guard的else语句,并且函数本身会在那里退出。
如果成功解开该值,则print(sa)语句将运行。
最后,让我们将嵌套的if语句转换为保护语句,看看如何轻松摆脱嵌套条件。
func guardStatements() { guard let f = first else{ print("nil value") return } guard let s = second else{ print("nil value") return } guard let t = third else{ print("nil value") return } print(f + " " + s + " " + t) } guardStatements() //prints first second third //Isn't the above code simpler than the below one? var first:String? = "first" var second:String? = "second" var third:String? = "third" if let f = first { if let s = second{ if let t = third{ print(f + " " + s + " " + t ) } else{ print(f + " " + s + " NA") } } else{ print(f + " NA") } } else{ print("NA") }
Swift guard只会检查不良情况。
如果在任何一种情况下都满足条件(坏情况),则函数将自行退出。
注意:guard let
和if let
之间的区别
保护声明使早期退出成为可能,重点是否定情况,而if条件则等待所有嵌套条件通过。
保护语句中的未包装值将可用于其余代码块,而无需再次强制/可选地重新包装。