2016-09-12 3 views
23

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

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

Моего инструктор сказал: «Если я вижу, что вы с помощью оператора паф, мы будем бороться» Им

+0

Пожалуйста, отредактируйте, чтобы включить обе версии кода - с и без "bang" –

ответ

23

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

+7

Будьте очень осторожны с синтаксисом 'string +" "+ string'. Это может привести к взрыву компиляции. Привязанные операторы '+' очень часто приводят к времени O (n!), Чтобы выяснить правильные типы. Это, вероятно, самая распространенная причина массового компиляции, которую я вижу в дикой природе. Интерполяция компилируется значительно быстрее. –

+0

Для меня «защита» подразумевает ошибку или ошибку. И вы могли бы иметь несколько из них отдельно. То есть guard someRequiredValue! = Nil else { return "error" } охранник другойCheck!= nil else { return "error" } return "normal return value" –

+1

@MattHorst Вы видели мое обновление о 'guard'? Я поставил его, чтобы показать, как он работает с отказом от ответственности, что он чаще используется в случае ошибки/сбоя. – JAL

5

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

Однако у 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 и может использовать его как известный не-нуль.

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

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

Я согласен с другими сообщениями, которые вам не нужны, чтобы использовать эту проверку для этого случая конкатенации строк. Тем не менее, я действительно думаю, что у меня это выше, чем с помощью охраны. Для меня охрана подразумевала бы ошибку/неудачу. –

16

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

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(_:) вместо этого.)

+1

Спасибо, Роб. Если бы я мог принять два ответа, я тоже согласился бы с вами. –

+1

Очевидно, это ограничивает, какое у вас форматирование. Если вы хотите вывести «Смит, Джон Джеймс» или «Смит, Джон», то это не сработает. И если небольшое изменение в спецификации требует большого изменения кода, тогда ваш код может быть неправильным. С исходным кодом это изменение было бы тривиальным. – gnasher729

+0

@ gnasher729 Правда.Трудно написать этот код таким образом, чтобы он был устойчивым против многих различных изменений, которые могут произойти. Один из способов облегчить добавление случайных новых полей (в частности, дополнительных), но сбой, если формат становится непоследовательным. Другой способ изменения в формате случайным образом, но становится очень сложным для обработки многих необязательных полей. Хорошим примером того, как это сделать что-то легко расширить, часто гораздо сложнее, чем кажется; нет ни одного ответа, который бы охватывал все базы. –

2

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

  1. if let
  2. guard
  3. if-else
  4. с использованием троичной оператора
  5. Nil сливающихся оператор

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

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

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

по

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

ИЛИ

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

0

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

Но обычно «если пусть ...» - лучший способ справиться с этим, потому что он сочетает в себе тест и разворачивание.

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

+4

Если есть «лучший способ справиться с этим», тогда, похоже, его инструктор не ошибается в конце концов .. – Insane

Смежные вопросы