Как избежать принудительной разворачивания переменной?
Как мне избежать использования! операция, выполняющая разворот силы, поскольку использование этого обычно является плохим вариантом.
Каков наилучший вариант с кодом, например следующим, где его использование делает код более простым и из-за проверки переменной! вызывается никогда не будет 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..." - лучший способ справиться с этим, потому что он объединяет тест и разворачивание.
Есть также ситуации, когда вы не говорите "если это ничто, это будет крушить, что плохо", но "если это нуль, то я хочу, чтобы он разбился" (обычно, потому что вы знаете, что это может быть только ноль, если есть ошибка где-то в вашем коде). В таком случае! делает именно то, что вы хотите.