2016-02-26 3 views
4

Скажем, у нас есть перечисление со связанными типами значений. В приведенном ниже примере два типа значений - это простой объект, который содержит изображение и URL для совместного использования.Сопоставление скоростного перечисления со связанными значениями

enum Content { 
    case Image(ShareableImage) 
    case Video(ShareableVideo) 
} 

Теперь давайте располагаем массивом видео и изображений.

let media: [Content] = [*a lot of enum cases inside here*] 

Весь код, который до сих пор не может быть каким-либо образом изменен в кодовой базе, мне нужно с ним работать.


Здесь начинается моя проблема:

Давайте фильтровать массив со средствами массовой информации только случаев изображения

let imageOnlyCases: [Content] = media.filter { item -> Bool in 

     switch item { 
     case .Image: return true 
     default: return false 
     } 
    } 

Следующий шаг, я хочу получить от массива перечисления в массив их ассоциированные значения

[Content] -> [ShareableImage] by using map. 

поэтому я делаю является

let shareablemages = imageOnlyCases.map { imageCase -> ShareableImage in 

     switch imageCase { 

     case .Image(let image): return image 
     default: return WHAT TO DO HERE? 
     } 
    } 

Вы видите, у меня есть проблемы с возвратом type..I знает, что случаи перечислений всех .Image..and Я хочу простую карту. Но быстрый синтаксис мне не помогает.

Любые идеи?

+0

Я бы вернул nil, так что у вас есть набор дополнительных значений, связанных с дополнительными параметрами, после чего вы можете отфильтровать его, чтобы избавиться от nil. – Greg

ответ

10

Вы можете вернуться image для случая .Image и nil в противном случае, в .flatMap операции (в «фильтр» из nil записей):

/* Example */ 
enum Foo { 
    case Bar(Int) 
    case Baz(Int) 
} 

let foo: [Foo] = [.Bar(1), .Bar(9),. Baz(3), .Bar(39), .Baz(5)] 

/* 1. using 'switch' */ 
let barOnlyValues: [Int] = foo.flatMap { 
    switch $0 { 
    case .Bar(let val): return val 
    case _: return nil 
    }} 

/* 2. alternatively, as pointed out in MartinR:s answer; 
     as you're only looking for a single case, the alternative 
     'if case let' clause could be preferred over 'switch':  */ 
let barOnlyValuesAlt: [Int] = foo.flatMap { 
    if case let .Bar(val) = $0 { return val } 
    else { return nil }}        

print(barOnlyValues) // [1, 9, 39] 

примененном к вашему прецеденту: обратите внимание, что вам не нужно выполнять фильтрация для создания imageOnlyCases массива, как вы можете применить выше, непосредственно на media массива:

/* 1. using switch */ 
let shareableImages : [ShareableImage] = media.flatMap { 
    switch $0 { 
    case .Image(let image): return image 
    case _: return nil 
    }} 

/* 2. 'if case let' alternative, as per MartinR:s suggestion */ 
let shareableImagesAlt : [ShareableImage] = media.flatMap { 
    if case let .Image(image) = $0 { return image } 
    else { return nil }} 

Отказ от ответственности: Я не могу вер ify ваш конкретный случай использования на практике, поскольку у меня нет доступа к классу/структуре ShareableImage.

(спасибо @MartinR за то, что .map{ ... }.flatMap{ ... } можно упростить до .flatMap{ ... }).

+0

Теперь вы были быстрее :) - Simpler: 'media.flatMap {...}' вместо отдельных вызовов map() и flatMap. –

+0

Кто-нибудь еще думает: «Если случай разрешен .Image (let image) = value {...}' очень странно выглядит? Я просто не получаю этот синтаксис. В книге Swift есть только один пример этого, и это необязательно для развертывания. – nekonari

+0

@nekonari пример в руководстве по языку ([шаблоны] (https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html)) действительно охватывает доступ к завернутому значению необязательно, но это всего лишь один пример сопоставления шаблонов с примерами «enum» в сочетании с привязкой к связанным значениям (-ам) в случае успешного совпадения шаблонов. В этом контексте «Необязательный » как и любой общий «enum», использует общий тип в некоторых (или нескольких) связанных значениях для случаев «enum». Сравнить w. 'switch' над' enum'. – dfri

1

Если гарантируется что только .Image случай может произойти то вы можете вызвать fatalError() во всех других случаях:

let shareableImages = imageOnlyCases.map { imageCase -> ShareableImage in 

    if case let .Image(image) = imageCase { 
     return image 
    } else { 
     fatalError("Unexpected content") 
    } 
} 

fatalError() заставляет программу немедленно прекратить. Это предназначено только для ситуаций, которые «не могут произойти», то есть найти ошибки .

Он удовлетворяет компилятору, поскольку функция отмечена как @noreturn.

Если вы не можете сделать эту гарантию, используйте flatMap() как предложено в другом ответе. Обратите внимание, что вы можете использовать if case здесь с рисунком вместо switch/case.

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