创建第一个中间名和姓氏时的可选项

时间:2018-04-25 19:06:29

标签: ios swift

我想创建一个功能,可以检查一个人是否输入了他们的中间名,或者该变量是否为空(&n;)(即无)。如果它不是空的,它将基本上打印人员的第一个,中间名和全名,如果不是,它应该忽略中间名并打印出名字和名字,如果值是' nil'(现在是)。无论出于何种原因,它都没有打印出没有中间名的person2FirstName和person2LastName(这就是我想要的)。

我这样做是为了在Swift中使用选项进行练习。在实践中,我有一个可怕的时间环绕它,虽然我知道它是一种在理论上保护你的代码的方法。我很感激你能给予的任何帮助。

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)"

2 个答案:

答案 0 :(得分:2)

简短回答:

使用if let代替nil进行测试。这会“展开”变量,使其不再是可选的。

而不是:

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

这样做:

if let unwrappedFoo = foo {
    doSomethingWith(unwrappedFoo) // No warnings!
}

答案很长:

这里似乎有很多变量,其中很多都是逻辑分组的。 Person1FirstName,Person1MiddleName,Person1LastName,Person2FirstName,... Person3FirstName,...等。您可以通过在结构中将这些组合在一起来简化这一过程,如下所示:

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 }
}

答案 1 :(得分:0)

对于这种情况,我使用??。如果可选值当前为零,则允许您访问可选值或备用值。

let first:String =  "Steve"
let middle:String? = nil  // fixed this
let last:String =  "Jones"

let fullName = "\(first) \(middle ?? "") \(last)"

唯一的问题是,当这个人没有中间名时,你最终会得到双倍的空间。在这种情况下,更好的解决方案是:

let fullName = [first, middle ?? "", last].filter( { !$0.isEmpty} ).joined(separator: " ")