Свіфт: тестування щодо необов’язкового значення у випадку перемикача


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. Додавання ?замість цього !мало б для мене певний сенс (я думаю, в дусі додаткового ланцюжка), але помилка компілятора не зникає (тобто насправді не розгортає необов’язкову).

Відповіді:


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 деякі / none є малими, тобто ви б використовували .some замість .Some
Адам

55

Починаючи з Xcode 7, «новий x?шаблон може бути використаний для збігу шаблонів з необов’язковими як синонім слова .some(x)». Це означає, що в Swift 2 та пізніших версіях відповіді rintaro також буде працювати:

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
Правда, однак ця відповідь була спочатку написана Оперативною програмою як оновлення питання, тому для нього це було незаперечно життєздатним рішенням; Я просто перемістив його до відповіді на вікі спільноти. Можливо, @GeorgeWS може пояснити, чому перемикання аргументів switch & case працює для його випадку використання?
Сліпп Д. Томпсон,

2
Я трохи загубився. яка різниця між вашими першими двома випадками? someValue?це якесь інше визначене значення, але case let val?це лише безпечна розгорнута версія someOptional?!
Мед

@Honey Це не реальний приклад коду; це просто варіація відповіді Рінтаро. Тож ідіть запитуйте його / її це питання - моя відповідь функціонально еквівалентна коду в його / її. Якщо б ви запитали у rintaro, я вважаю, що відповідь буде 1. він відображає те, що є у пов'язаних документах Apple; 2. він лише демонструє синтаксис; він не досягає чітких цілей розрахунку чи бізнес-логіки.
Сліпп Д. Томпсон,

@Honey Також відповідь rintaro була спочатку написана для Swift 1.x та оновлена ​​для Swift 2. Можливо, версія letвже не компілюється. Зараз я не пам’ятаю, чому це спрацювало б у ті часи.
Сліпп Д. Томпсон,

10

У Swift 4 ви можете використовувати необов’язково: ExprevableByNilLiteral від Apple, щоб обернути необов’язково

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.