如何避免强行展开变量?

Tre*_*ood 27 swift

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

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

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

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

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

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

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

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)"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

JAL*_*JAL 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)"
}
Run Code Online (Sandbox Code Playgroud)

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

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

考虑return firstName + " " + lastName.有关字符串插值可能返回意外结果的情况,请参阅Swift中字符串插值和字符串初始值设定项之间的差异.

  • 要非常小心`string +""+ string`语法.这可能导致编译时间爆炸.链式`+`运算符经常导致O(n!)时间找出正确的类型.它可能是我在野外看到的大量编译时间的最常见原因.插值编译得更快,更快. (8认同)
  • @Honey`+`函数被大量重载以处理许多不同的类型和协议.编译器结束搜索许多类型的组合,试图找到与提供的类型匹配的类型.请参阅http://swiftdoc.org/v2.2/operator/pls/在某些情况下,它可以正常工作,特别是在小代码片段中,但它是类型检查器中组合爆炸的一个非常非常常见的原因.不是说它应该是这样的; 这是编译器的问题.但就在上周,我有两个不同的团队抱怨疯狂的构建时间,结果证明它是一个"+"链. (2认同)

Rob*_*ier 16

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

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

这只是将名称的所有非零部分与空格连接起来.这里的其他答案也很好,但它们不能扩展到添加更多可选部分(如"Mr."标题或"Jr."后缀).

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

  • @Honey有很多地方我会故意使应用程序崩溃,但是我使用`precondition`或`fatalError`来解决这些问题,以便明确我的意图并提供解释(特别是因为我使用自动记录先前的自定义包装器崩溃到Loggly和Crashlytics;你不能用`!`来做到这一点.`!`会崩溃,但在崩溃报告中给你很少的上下文.`IBOutlet`通常应该是隐式解包的选项(`UILabel!`),因此不需要在使用时添加`!`.我不是说你永远不会强迫打包,但非常罕见. (3认同)

Mat*_*rst 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)"
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

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

if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber < secondNumber {
    print("\(firstNumber) < \(secondNumber)")
}
Run Code Online (Sandbox Code Playgroud)

  • 对于这种字符串连接的情况,我同意你不需要像这样使用if检查的其他帖子.但是,我确实认为我上面的方法比使用后卫更好.对我来说,警卫意味着错误/失败的情况. (2认同)