Swift可选

时间:2020-02-23 14:44:03  来源:igfitidea点击:

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 letif let之间的区别

  • 保护声明使早期退出成为可能,重点是否定情况,而if条件则等待所有嵌套条件通过。

  • 保护语句中的未包装值将可用于其余代码块,而无需再次强制/可选地重新包装。