This question already has answers here:
Swift 2 - Proper way to concatenate optional strings?
(8个答案)
去年关门了。
我想创建一个函数来检查一个人是否输入了中间名,或者变量是否为“空”(即nil)。如果不是空的,它基本上会打印出人的名字,中间名和全名,如果不是,它应该忽略中间名,如果值是“nil”(即是),则打印出名字和姓氏。不管出于什么原因,它都不会打印出没有中间名的person2FirstName和person2LastName(这就是我想要它做的)。
我这么做是为了练习快速使用选项。在实践中,我很难把自己的脑袋放在这上面,尽管我知道这是从理论上保护代码的一种方法。如果你能帮我,我将不胜感激。
let person2FirstName: String =  "Steve"
let person2MiddleName: String? = "nil"
let person2LastName: String =  "Jones"

if person2MiddleName != nil {
"\(person2FirstName) \(person2MiddleName) \(person2LastName)"
} else {
"\(person2FirstName) \(person2LastName)"
}

我一直有这些错误:
main.swift:14:23: warning: string interpolation produces a debug description for an optional value; did you mean to make this explicit?
"\(person2FirstName) \(person2MiddleName) \(person2LastName)"
                      ^~~~~~~~~~~~~~~~~~~
main.swift:14:24: note: use 'String(describing:)' to silence this warning
"\(person2FirstName) \(person2MiddleName) \(person2LastName)"
                      ~^~~~~~~~~~~~~~~~~~
                       String(describing:  )
main.swift:14:24: note: provide a default value to avoid this warning
"\(person2FirstName) \(person2MiddleName) \(person2LastName)"
                      ~^~~~~~~~~~~~~~~~~~
                                         ?? <#default value#>
main.swift:14:1: warning: string literal is unused
"\(person2FirstName) \(person2MiddleName) \(person2LastName)"
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.swift:16:1: warning: string literal is unused
"\(person2FirstName) \(person2LastName)"

最佳答案

简短回答:
使用if let而不是针对nil进行测试。这个“展开”变量,使其不再是可选的。
而不是:

if foo != nil {
    doSomethingWith(foo) // WARNING: foo is optional!
}

执行以下操作:
if let unwrappedFoo = foo {
    doSomethingWith(unwrappedFoo) // No warnings!
}

长答案:
这里似乎有很多变量在起作用,其中许多是逻辑分组的。Person1FirstName,Person1MiddleName,Person1LastName,Person2FirstName。。。姓名。。。等等。你可以通过将它们组合在一个结构中来简化这一点,比如:
struct Person {
    let firstName: String
    let middleName: String?
    let lastName: String
}

现在我们可以添加一个方便的初始值设定项和一个方便的属性来生成全名:
struct Person {
    let firstName: String
    let middleName: String?
    let lastName: String

    init(firstName: String, middleName: String? = nil, lastName: String) {
        self.firstName = firstName
        self.middleName = middleName
        self.lastName = lastName
    }

    var fullName: String {
        if let middleName = self.middleName {
            return "\(self.firstName) \(middleName) \(self.lastName)"
        } else {
            return "\(self.firstName) \(self.lastName)"
        }
    }
}

(初始值设定项并不是绝对必要的,因为编译器会自动为我们生成一个初始值设定项,但是使用手动编写的初始值设定项,我们可以将middleName默认为nil,这样就不必在创建没有中间名的Person时实际指定该初始值设定项)
然后你就可以:
let person = Person(firstName: "Joe", lastName: "Blow")
print(person.fullName) // outputs "Joe Blow"

这件事的好处是,稍后,如果需要的话,我们可以在Person结构中添加额外的特性,而不必破坏现有的使用它的代码。例如,假设我们想添加处理真正长的名字的能力,其中有一个以上的中间名。我们可以将middleName替换为middleNames数组属性,然后执行如下操作:
struct Person {
    let firstName: String
    let middleNames: [String]
    let lastName: String

    init(firstName: String, middleName: String? = nil, lastName: String) {
        // continues to work exactly as before!
        self.firstName = firstName
        // map on an optional just means "run the closure if the value's not nil."
        // We could also use if let instead.
        self.middleNames = middleName.map { [$0] } ?? []
        self.lastName = lastName
    }

    init(firstName: String, middleNames: [String], lastName: String) {
        // new initializer that takes multiple middle names
        self.firstName = firstName
        self.middleNames = middleNames
        self.lastName = lastName
    }

    var fullName: String {
        let names = [self.firstName] + self.middleNames + [self.lastName]

        return names.join(separator: " ")
    }

    // and so that old code that called the `middleName` property continues to work:
    var middleName: String? { return self.middleNames.first }
}

09-30 12:43