Swift: проверка на необязательное значение в случае переключателя

94

Как в Swift я могу написать регистр в операторе switch, который проверяет переключаемое значение на содержание необязательного , пропуская регистр, если необязательный параметр содержит nil?

Вот как я себе это представляю:

let someValue = 5
let someOptional: Int? = nil

switch someValue {
case someOptional:
    // someOptional is non-nil, and someValue equals the unwrapped contents of someOptional
default:
    // either, someOptional is nil, or someOptional is non-nil but someValue does not equal the unwrapped contents of someOptional
}

Если я просто пишу это именно так, компилятор жалуется , что someOptionalне разворачивали, но если я явно разворачивать его, добавив !к концу, я, конечно , получаю ошибку во время выполнения в любое время someOptionalсодержит nil. Добавление ?вместо !имело бы для меня некоторый смысл (я полагаю, в духе необязательной цепочки), но не устраняет ошибку компилятора (т.е. фактически не разворачивает необязательное).

Джордж WS
источник

Ответы:

113

Необязательно выглядит примерно enumтак:

enum Optional<T> : Reflectable, NilLiteralConvertible {
    case none
    case some(T)

    // ...
}

Таким образом, вы можете сопоставить их как обычные шаблоны сопоставления «Связанные значения» :

let someValue = 5
let someOptional: Int? = nil

switch someOptional {
case .some(someValue):
    println("the value is \(someValue)")
case .some(let val):
    println("the value is \(val)")
default:
    println("nil")
}

Если вы хотите найти совпадение someValue, используя выражение защиты :

switch someValue {
case let val where val == someOptional:
    println(someValue)
default:
    break
}

А для Swift> 2.0

switch someValue {
case let val where val == someOptional:
    print("matched")
default:
    print("didn't match; default")        
}
Ринтаро
источник
5
Обратите внимание, что в Swift 3 some / none пишутся в нижнем регистре, то есть вы должны использовать .some вместо .Some
Адам
55

Начиная с Xcode 7, «новый x?шаблон может использоваться для сопоставления шаблонов с дополнительными параметрами в качестве синонима для .some(x)». Это означает, что в Swift 2 и более поздних версиях также будет работать следующий вариант ответа Ринтаро :

let knownValue = 5

switch someOptional {
case knownValue?:
    // Contents of someOptional are knownValue, defined above.
case let otherValue?:
    // Contents of someOptional are *any* non-nil value not already tested for.
    // Unwrapped contents are assigned to otherValue for use inside this case.
default:
    // someOptional is nil.
}
Слипп Д. Томпсон
источник
3
Вопрос в том, чтобы сопоставить необязательное значение с необязательным, этот ответ - наоборот.
Martin R
2
Верно, однако этот ответ был первоначально написан OP как обновление вопроса, поэтому для него это было неопровержимо жизнеспособным решением; Я просто переместил его в ответ сообщества вики. Возможно, @GeorgeWS может прояснить, почему переключение аргументов switch и case работает для его варианта использования?
Слипп Д. Томпсон,
2
Я немного заблудился. в чем разница между вашими первыми двумя случаями? someValue?есть какое-то другое определенное значение, но case let val?это просто безопасная развернутая версия someOptional?!
Дорогая
@Honey Это не пример кода из реального мира; это просто вариант ответа Ринтаро. Так что задавайте ему / ей этот вопрос - мой ответ функционально эквивалентен коду в его / ее. Если бы вы спросили Ринтаро, я полагаю, что ответ был бы: 1. он отражает то, что находится в связанных документах Apple; 2. он только демонстрирует синтаксис; он не выполняет четких расчетов или целей бизнес-логики.
Слипп Д. Томпсон
@Honey Кроме того, ответ rintaro изначально был написан для Swift 1.x и обновлен для Swift 2. Возможно, версия без него letбольше не компилируется. Я не могу вспомнить прямо сейчас, почему это могло сработать тогда.
Слипп Д. Томпсон
10

В Swift 4 вы можете использовать Optional: ExpressibleByNilLiteral от Apple, чтобы обернуть optional

https://developer.apple.com/documentation/swift/optional

пример

enum MyEnum {
    case normal
    case cool
}

некоторые

let myOptional: MyEnum? = MyEnum.normal

switch smyOptional {
    case .some(.normal): 
    // Found .normal enum
    break

    case .none: 
    break

    default:
    break
}

никто

let myOptional: MyEnum? = nil

switch smyOptional {
    case .some(.normal): 
    break

    case .none: 
    // Found nil
    break

    default:
    break
}

по умолчанию

let myOptional: MyEnum? = MyEnum.cool

switch smyOptional {
    case .some(.normal): 
    break

    case .none: 
    break

    default:
    // Found .Cool enum
    break
}

Перечислить со значением

enum MyEnum {
    case normal(myValue: String)
    case cool
}

некоторая ценность

let myOptional: MyEnum? = MyEnum.normal("BlaBla")

switch smyOptional {
case .some(.normal(let myValue)) where myValue == "BlaBla":
    // Here because where find in my myValue "BlaBla"
    break

// Example for get value
case .some(.normal(let myValue)):
    break

// Example for just know if is normal case enum
case .some(.normal):
    break

case .none:
    break

default:

    break
}
ЯннСтеф
источник
Вы упомянули, ExpressibleByNilLiteralно тогда это фактически не используется в объявлениях перечисления и т. Д. Что это такое?
pkamb