Использование @unknown default в перечислении swift 5: как подавить предупреждение по умолчанию никогда не будет выполняться?

Скажем, у меня есть существующий код следующим образом:

enum SomeEnumCases {
  case existing
  case alreadyExisting
}

func doSomething(withEnums enumCase: SomeEnumCases) {
  switch enumCase {
  case .existing:
    print("This case was already existing")
  case .alreadyExisting:
    print("This case was already existing too...")
  }
}

Теперь, если бы я добавил новый случай в перечисление, вышеприведенная функция показала бы ошибку компиляции, говорящую, что случай переключателя должен быть исчерпывающим, и я был бы ВЫНУЖДЕН обработать новый отсутствующий случай. Я бы добавил третий случай в оператор switch или добавил оператор по умолчанию.

Теперь я приказываю обрабатывать такие непредвиденные случаи перечисления, я хотел бы добавить случай @unknown default к существующей функции выше. Единственная проблема в том, что теперь он выдаст мне предупреждение о том, что Default will never be executed.

Итак, вопрос в том, как мне защитить свое перечисление от будущего, чтобы я мог:

  1. Исчерпывающая обработка всех текущих случаев enum, И
  2. Иметь механизм обработки по умолчанию для будущего неизвестного случая, И
  3. Предупреждение отображается только при добавлении новых обращений, и эти обращения должны обрабатываться обращением по умолчанию.

Это означает, что следующий код НЕ ДОЛЖЕН выдавать предупреждения:

enum SomeEnumCases {
  case existing
  case alreadyExisting
}

func doSomething(withEnums enumCase: SomeEnumCases) {
  switch enumCase {
  case .existing:
    print("This case was already existing")
  case .alreadyExisting:
    print("This case was already existing too...")
  @unknown default: // <-- warning: Default will never be executed: should be suppressed
    print("Alright, this is something new and exciting !!")
  }
}

но следующий код ДОЛЖЕН выдавать предупреждение:

enum SomeEnumCases {
  case existing
  case alreadyExisting
  case new
}

func doSomething(withEnums enumCase: SomeEnumCases) {
  switch enumCase { // <-- warning: Switch must be exhaustive: This should stay.
  case .existing:
    print("This case was already existing")
  case .alreadyExisting:
    print("This case was already existing too...")
  @unknown default:
    print("Alright, this is something new and exciting !!")
  }
}

Возможно ли это через @unknown или как-то иначе?


person Mehul Parmar    schedule 30.03.2019    source источник
comment
Как и обычное значение по умолчанию, @unknown default соответствует любому значению; это универсальный случай. Однако компилятор выдаст предупреждение, если все известные элементы перечисления еще не сопоставлены. Для лучшего понимания перейдите по этой ссылке: github .com/apple/swift-evolution/blob/master/proposals/   -  person sinner    schedule 30.03.2019


Ответы (1)


Предупреждение, вероятно, несколько вводит в заблуждение, поскольку spec (акцент добавлено):

Незамороженное перечисление — это особый вид перечисления, который может получить новые случаи перечисления в будущем — даже после того, как вы скомпилируете и отправите приложение. Переключение незафиксированного перечисления требует дополнительного внимания. Когда авторы библиотеки помечают перечисление как незамороженное, они оставляют за собой право добавлять новые случаи перечисления, и любой код, взаимодействующий с этим перечислением, должен иметь возможность обрабатывать эти будущие случаи без повторной компиляции. Только стандартная библиотека, наложения Swift для платформ Apple и код C и Objective-C могут объявлять незамороженные перечисления. Перечисления, которые вы объявляете в Swift, не могут быть разблокированы.

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

Похоже, что в Swift 5 нет поддерживаемого способа делать то, что вы хотите, и некоторые признаки того, что добавление случаев рассматривается как критическое изменение, поскольку оно может/нарушит двоичную совместимость, но Swift - это постоянно движущаяся цель...

person CRD    schedule 30.03.2019
comment
Это позор, так как это оттолкнет большинство разработчиков от использования этого нового корпуса. Если они захотят его использовать, им придется иметь дело с постоянными предупреждениями в своем проекте о том, что Default никогда не будет выполняться. Если в вашем проекте много перечислений и вы хотите проверить свой код на будущее, это становится несостоятельным, поскольку вы получите многочисленные предупреждения, которые ни один разработчик не хочет иметь в своем проекте. - person AdamM; 18.04.2019
comment
@AdamM - При использовании с правильным типом перечисления предупреждений не будет, возможно, было бы лучше, если бы компилятор Swift выдавал ошибку при использовании с неправильным типом, чтобы избежать путаницы. Традиционное перечисление — это тип, определяемый набором литеральных значений, а в семействе C этот тип является слабым и может быть расширен путем добавления дополнительных литералов. Тип enum, который использует Swift, по сути представляет собой несвязанное объединение с тегами, они существуют во многих языках и могут быть созданы в C-семействе с использованием комбинации enum, union и struct. [продолжение...] - person CRD; 19.04.2019
comment
[...продолжение] Учитывая (текущий) способ, которым Swift компилирует свои перечисления, добавление нового случая может нарушить бинарную совместимость между существующим скомпилированным кодом и существующими случаями, поэтому требуется перекомпиляция кода при появлении любых новых случаев добавлены. Это не значит, что Swift не может поддерживать не замороженные перечисления в стиле Swift, но они (предположительно) взвешивают компромиссы и предпочитают не делать этого (но Swift - постоянно движущаяся цель...) - person CRD; 19.04.2019