当前位置: 首页 > 面试题库 >

什么时候应该将可选值与nil比较?

卫弘懿
2023-03-14
问题内容

通常,您需要编写如下代码:

if someOptional != nil {
    // do something with the unwrapped someOptional e.g.       
    someFunction(someOptional!)
}

这似乎有点冗长,而且我还听说使用!强制解包运算符可能是不安全的,最好避免使用。有没有更好的方法来解决这个问题?


问题答案:

几乎总是没有必要检查可选项是否没有nil。几乎唯一需要这样做的时间是,如果它的nil-ness是 唯一
要了解的内容–您不在乎值的含义,而不必在意nil

在大多数其他情况下,还有一些Swift速记可以更安全,简洁地if为您完成任务。

如果不是,则使用该值nil

代替:

let s = "1"
let i = Int(s)

if i != nil {
    print(i! + 1)
}

您可以使用if let

if let i = Int(s) {
    print(i + 1)
}

您也可以使用var

if var i = Int(s) {
    print(++i)  // prints 2
}

但请注意,这i将是 本地 副本-对其所做的任何更改i都不会影响原始可选内容中的值。

您可以在单个内解开多个可选选项if let,以后的选项可以取决于以前的选项:

if let url = NSURL(string: urlString),
       data = NSData(contentsOfURL: url),
       image = UIImage(data: data)
{
    let view = UIImageView(image: image)
    // etc.
}

您还where可以在未包装的值中添加子句:

if let url = NSURL(string: urlString) where url.pathExtension == "png",
   let data = NSData(contentsOfURL: url), image = UIImage(data: data)
{ etc. }

替换nil为默认值

代替:

let j: Int
if i != nil {
    j = i
}
else {
    j = 0
}

要么:

let j = i != nil ? i! : 0

您可以使用nil-coalescing运算子??

// j will be the unwrapped value of i,
// or 0 if i is nil
let j = i ?? 0

将可选与非可选等同

代替:

if i != nil && i! == 2 {
    print("i is two and not nil")
}

您可以检查可选值是否等于非可选值:

if i == 2 {
    print("i is two and not nil")
}

这也适用于比较:

if i < 5 { }

nil总是等于其他nils,并且小于任何非nil值。

小心!这里可能有陷阱:

let a: Any = "hello"
let b: Any = "goodbye"
if (a as? Double) == (b as? Double) {
    print("these will be equal because both nil...")
}

调用可选方法(或读取属性)

代替:

let j: Int
if i != nil {
    j = i.successor()
}
else {
   // no reasonable action to take at this point
   fatalError("no idea what to do now...")
}

您可以使用可选的链接?.

let j = i?.successor()

注意,j现在也将是可选的,以解决该fatalError情况。稍后,您可以在此答案中使用其他技术之一来处理js的可选性,但是您通常可以将实际展开可选对象的时间推迟到很久以后,有时甚至根本不进行。

顾名思义,您可以将它们链接起来,因此可以编写:

let j = s.toInt()?.successor()?.successor()

可选链接也可用于下标:

let dictOfArrays: ["nine": [0,1,2,3,4,5,6,7]]
let sevenOfNine = dictOfArrays["nine"]?[7]  // returns {Some 7}

和功能:

let dictOfFuncs: [String:(Int,Int)->Int] = [
      "add":(+),
      "subtract":(-)
]

dictOfFuncs["add"]?(1,1)  // returns {Some 2}

分配给可选属性

代替:

if splitViewController != nil {
    splitViewController!.delegate = self 
}

您可以 通过 可选链进行分配:

splitViewController?.delegate = self

只有在splitViewControllernil分配情况下才会发生。

使用值,如果不是nil或,则使用值(Swift 2.0中的新增功能)

有时在函数中,您需要编写一小段代码来检查可选项,如果是nil,则尽早退出该函数,否则继续进行。

您可以这样写:

func f(s: String) {
    let i = Int(s)
    if i == nil { fatalError("Input must be a number") }
    print(i! + 1)
}

或避免强制展开,例如:

func f(s: String) {
    if let i = Int(s) {
        print(i! + 1)
    }
    else { 
        fatalErrr("Input must be a number")
    }
}

但是最好将错误处理代码保持在检查的顶部。这也可能导致令人不快的嵌套(“厄运金字塔”)。

相反,您可以使用guard,它类似于if not let

func f(s: String) {
    guard let i = Int(s)
        else { fatalError("Input must be a number") }

    // i will be an non-optional Int
    print(i+1)
}

else零件 必须 退出保护值的范围,例如a returnfatalError,以确保该保护值对其余范围有效。

guard不限于功能范围。例如以下内容:

var a = ["0","1","foo","2"]
while !a.isEmpty  {
    guard let i = Int(a.removeLast())
        else { continue }

    print(i+1, appendNewline: false)
}

版画321

循环处理序列中的非零项目(Swift 2.0中的新增功能)

如果有一系列可选参数,则可以用于for case let _?遍历所有非可选元素:

let a = ["0","1","foo","2"]
for case let i? in a.map({ Int($0)}) {
    print(i+1, appendNewline: false)
}

版画321。这是将模式匹配语法用于可选内容,即变量名后跟?

您还可以在switch语句中使用此模式匹配:

func add(i: Int?, _ j: Int?) -> Int? {
    switch (i,j) {
    case (nil,nil), (_?,nil), (nil,_?):
        return nil
    case let (x?,y?):
        return x + y
    }
}

add(1,2)    // 3
add(nil, 1) // nil

循环直到函数返回nil

很像if let,您还可以编写while let和循环直到nil

while let line = readLine() {
    print(line)
}

您还可以编写while var(要if var应用类似的警告)。

where 子句在这里也起作用(并终止循环,而不是跳过):

while let line = readLine() 
where !line.isEmpty {
    print(line)
}

将可选参数传递给采用非可选参数并返回结果的函数

代替:

let j: Int
if i != nil {
    j = abs(i!)
}
else {
   // no reasonable action to take at this point
   fatalError("no idea what to do now...")
}

您可以使用可选的map运算符:

let j = i.map { abs($0) }

这是非常相似的可选链接,但对于当你需要的非可选值传递 函数作为参数。与可选链接一样,结果将是可选的。

无论如何,如果您想要一个可选的,这是很好的。例如,reduce1like
reduce,但是使用第一个值作为种子,如果数组为空,则返回一个可选值。您可以这样写(使用guard前面的关键字):

extension Array {
    func reduce1(combine: (T,T)->T)->T? {

        guard let head = self.first
            else { return nil }

        return dropFirst(self).reduce(head, combine: combine)
    }
}

[1,2,3].reduce1(+) // returns 6

但是您可以选择map.first属性,然后返回该属性:

extension Array {
    func reduce1(combine: (T,T)->T)->T? {
        return self.first.map {
            dropFirst(self).reduce($0, combine: combine)
        }
    }
}

传递一个可选参数到一个接受可选参数并返回结果的函数中,避免烦人的双可选参数

有时,您想要类似于的东西map,但是您要调用的函数 本身 返回一个可选的。例如:

// an array of arrays
let arr = [[1,2,3],[4,5,6]]
// .first returns an optional of the first element of the array
// (optional because the array could be empty, in which case it's nil)
let fst = arr.first  // fst is now [Int]?, an optional array of ints
// now, if we want to find the index of the value 2, we could use map and find
let idx = fst.map { find($0, 2) }

但现在idx的类型为Int??,是双精度可选。相反,您可以使用flatMap,将结果“展平”为单个可选内容:

let idx = fst.flatMap { find($0, 2) }
// idx will be of type Int? 
// and not Int?? unlike if `map` was used


 类似资料:
  • 所以我正在学习Comparator和Comparable,我有以下问题。我有一门课: 另一个类Name实现了可比较的,在构造函数中有两个String。我不完全理解的是比较器的功能,我读过Java留档,我知道它用于对元素进行不同的排序,而不改变我的例子中的名称类它也可以在某些情况下允许空值,但是这个我的类构造函数中的声明工作正常,我根本不需要在PhoneBook类中实现比较器接口: 并实现了我希望它

  • 问题内容: 我知道他们两个都禁用了Nagle的算法。 我什么时候应该/不应该使用它们中的每一个? 问题答案: 首先,不是所有人都禁用Nagle的算法。 Nagle的算法用于减少有线中更多的小型网络数据包。该算法是:如果数据小于限制(通常是MSS),请等待直到收到先前发送的数据包的ACK,同时累积用户的数据。然后发送累积的数据。 这将对telnet等应用程序有所帮​​助。但是,在发送流数据时,等待A

  • 问题内容: 在该类中,有两个字符串,和。 有什么不同?我什么时候应该使用另一个? 问题答案: 如果你的意思是和则: 用于在文件路径列表中分隔各个文件路径。考虑在上的环境变量。您使用a分隔文件路径,因此在上将是;。 是或用于拆分到特定文件的路径。例如在上,或

  • 问题内容: 这不是一个关于之间的差异问题 和 。 我知道对象不能接受键或值条目的值,它是同步集合,并且使用的内存比少。 我想知道哪种情况更适合使用a 而不是a 。 问题答案: 这不是一个关于之间的差异问题和 好吧,真的。。。 我想知道哪种情况更适合使用a 而不是a 。 正是在您 想要 两者之间的差异时: 当您想在Java 1.1上运行时 当您希望每个操作都进行同步时(只要您从不迭代它,就可以得到一

  • 问题内容: 在集成我以前从未使用过的Django应用程序时,我发现了用于定义类中函数的两种不同方式。作者似乎非常有意地使用了它们。第一个是我自己经常使用的: 另一个是我不使用的,主要是因为我不知道何时使用它,以及什么用途: 在Python文档中,装饰器的解释如下: 类方法将类作为隐式第一个参数接收,就像实例方法接收实例一样。 所以我想指的是自己(而不是实例)。我不完全理解为什么会这样,因为我总是可

  • 问题内容: Java的允许值,并同时允许布尔值,和。我已经开始将s 转换为s。这可能导致测试崩溃,例如 测试时 似乎人为且容易出错。 何时将s与空值一起使用是否有用?如果从不,那么包装对象的主要优点是什么? 更新:有很多有价值的答案,我在自己的答案中总结了其中一些。我充其量只是Java的中级课程,因此我尝试展示了一些我认为有用的东西。请注意,问题是“用词不正确”(布尔值不能“具有空值”),但如果其