Как избежать принудительной разворачивания переменной?

Как мне избежать использования! операция, выполняющая разворот силы, поскольку использование этого обычно является плохим вариантом.

Каков наилучший вариант с кодом, например следующим, где его использование делает код более простым и из-за проверки переменной! вызывается никогда не будет 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

Ответ 1

Используйте конструкции if let или guard:

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. См. Разница между строковой интерполяцией и инициализатором строк в Swift для случаев, когда интерполяция строк может возвращать неожиданный результат.

Ответ 2

Ваш инструктор, в общем, правдивый. Определенно в этом случае. Нет причин для создания этого особого случая и принудительного дублирования кода.

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

Это просто объединяет все ненулевые части имени с пробелами. Другие ответы здесь также прекрасны, но они также не масштабируются для добавления дополнительных опций (например, "Mr." или "Jr." ).

(Это синтаксис Swift3. Swift 2 очень похож, вместо него joinWithSeparator(_:).)

Ответ 3

То, что вы сделали, будет работать, и действительно, как только вы это знаете, нет, используя! это правильный способ принудительно развернуть его.

Однако Swift имеет функцию под названием Необязательное связывание (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 и можете использовать его как известный не-nil.

Вы также можете связать их так, что у вас есть доступ к нескольким временным константам и не нужно связывать операторы if. И вы можете даже использовать предложение where для оценки необязательного условия. Опять же, из документов Apple выше:

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

Ответ 4

Прежде чем разворачивать необязательную переменную, вы должны проверить nil, иначе ваше приложение выйдет из строя, если переменная содержит nil. И проверки могут выполняться несколькими способами, например:

  • if let
  • guard
  • if-else
  • с использованием тернарного оператора
  • Нил-коалесцирующий оператор

И какой из них использовать полностью зависит от требования.

Вы можете просто заменить этот код

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

по

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

ИЛИ

вы также можете использовать оператор объединения Nil (a? b) разворачивает необязательный а, если он содержит значение или возвращает значение по умолчанию b, если a равно nil.

Ответ 5

В этом случае ваш инструктор ошибочен. Ваша функция абсолютно безопасна. middleName не изменится от нуля до нуля за вашей спиной. Ваша функция может упасть, если вы произведете какую-либо орфографическую ошибку, и введите имя другой переменной вместо middleName, но это все равно будет ошибкой, и авария приведет вас к ошибке.

Но обычно "if let..." - лучший способ справиться с этим, потому что он объединяет тест и разворачивание.

Есть также ситуации, когда вы не говорите "если это ничто, это будет крушить, что плохо", но "если это нуль, то я хочу, чтобы он разбился" (обычно, потому что вы знаете, что это может быть только ноль, если есть ошибка где-то в вашем коде). В таком случае! делает именно то, что вы хотите.