如何避免强行展开变量?

时间:2016-09-12 16:50:02

标签: swift

如何避免使用!使用此功能解压缩操作通常是一个不好的选择。

使用它的代码有什么更好的选择,使用它会使代码看起来更简单,因为if检查变量!被召唤永远不会是零,所以不能崩溃。

我的导师向我们介绍了bang(!)操作员,然后告诉我们再也不要使用它了。告诉我们为什么当然,如果可选项为nil,它将使我们的应用程序崩溃。

然而,我发现自己处于这样的情况下,爆炸操作员似乎是最简洁和安全的选择。

func fullName() -> String {
    if middleName == nil {
        return "\(firstName) \(lastName)"
    }else{
        return "\(firstName) \(middleName!) \(lastName)"
    }
}

有没有更好的方法来做这样的事情?

此外,如果有人想知道,这里是完整的课程。

class CPerson{
    var firstName: String
    var middleName: String?
    var lastName: String

    init(firstName: String, middleName: String?, lastName: String) {
        self.firstName = firstName
        self.middleName = middleName
        self.lastName = lastName
    }
    convenience init(firstName: String, lastName: String) {
        self.init(firstName: firstName, middleName: nil, lastName: lastName)
    }
    func fullName() -> String {
        if middleName == nil {
            return "\(firstName) \(lastName)"
        }else{
            return "\(firstName) \(middleName!) \(lastName)"
        }
    }
}

我的导师说"如果我看到你使用爆炸操作员,我们就会打架" O_O

5 个答案:

答案 0 :(得分:24)

使用if letguard结构:

func fullName() -> String {
    if let middleName = middleName {
        return "\(firstName) \(middleName) \(lastName)"

    } else {
        return "\(firstName) \(lastName)"
    }
}

func fullName() -> String {
    guard let middleName = middleName else {
        return "\(firstName) \(lastName)"
    }
    return "\(firstName) \(middleName) \(lastName)"
}

我已将guard语句用于完整性,但正如其他人所评论的那样,这在错误/失败案例中更常用。

我还建议不要对字符串使用字符串插值。它们已经是字符串,不需要在新字符串中使用每个名称的description

考虑return firstName + " " + lastName。有关字符串插值可能返回意外结果的情况,请参阅Difference between String interpolation and String initializer in Swift

答案 1 :(得分:16)

从广义上讲,你的导师是正确的。绝对是在这种情况下。没有理由将这种特殊情况作为特殊情况并强制重复代码。

func fullName() -> String {
    return [firstName, middleName, lastName] // The components
        .flatMap{$0}            // Remove any that are nil
        .joined(separator: " ") // Join them up
}

这只是用空格连接名称的所有非零部分。这里的其他答案也很好,但是他们也不会扩展以添加更多可选部分(例如" Mr。" title或" Jr。"后缀)

(这是Swift3语法.Swift 2非常相似,而是joinWithSeparator(_:)代替。)

答案 2 :(得分:5)

你所做的将会奏效,而且,一旦你知道它不是零,使用!是一种强制解开它的正确方法。

但是,Swift具有名为Optional Binding(https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html)的功能。

在你的情况下,它会是这样的:

func fullName() -> String {
        if let middle = middleName {
            return "\(firstName) \(middleName) \(lastName)"
        } else {
            return "\(firstName) \(lastName)"
        }
    }

可选绑定的作用是,正如Apple在上面的链接中所说,“你使用可选绑定来确定一个可选项是否包含一个值,如果是,则使该值可用作临时常量或变量”。因此,在括号内,您可以访问middle,并可以将其用作已知的非零。

您还可以链接这些链接,以便您可以访问多个临时常量,而不需要链接if语句。您甚至可以使用where子句来评估可选条件。再次来自Apple的上述文档:

if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber < secondNumber {
    print("\(firstNumber) < \(secondNumber)")
}

答案 3 :(得分:2)

在展开可选变量之前,您必须检查nil,否则如果变量包含nil,您的应用就会崩溃。 检查可以通过以下几种方式执行:

  1. if let
  2. guard
  3. if-else
  4. 使用三元运算符
  5. Nil coalescing operator
  6. 完全使用哪一个取决于要求。

    您只需替换此代码

    即可
    if middleName == nil {
        return "\(firstName) \(lastName)"
    }else{
        return "\(firstName) \(middleName!) \(lastName)"
    }
    

    通过

    return "\(firstName)\(middleName != nil ? " \(middleName!) " : " " )\(lastName)"
    

    OR

    如果a包含值,您也可以使用 Nil coalescing operator (a ?? b)展开可选的a,如果a为n,则返回默认值b。

答案 4 :(得分:0)

在这种情况下,你的导师错了。你的功能绝对安全。 middleName不会在背后从零变为零。如果你发出一些拼写错误,你的函数可能会崩溃,并输入一个不同的变量而不是middleName的名称,但无论如何这将是一个错误,崩溃将导致你的错误。

但通常“如果让......”是处理这个问题的更好方法,因为它结合了测试和解包。

还有一些情况你不会说“如果它是零,它会崩溃,那是坏的”,但“如果它是零,那么我希望它崩溃”(通常因为你知道它只能是零,如果有的话代码中某处的错误)。在这种情况下 !完全符合你的要求。