2015-11-03 6 views
11

Скажем, у меня есть массив AnyObject.Фильтрация массива Swift [AnyObject] по типу

let grabBag: [AnyObject] = [ "Tom", 4, "Dick", NSObject(), "Harry" ] 

, и я хочу, чтобы бросить его в массив Strings, извлекая только те элементы, которые на самом деле Strings. Я бы ожидать, что это работает:

let strings = grabBag.filter{ $0 is String } as! [String]  // 1 

но дает ошибку 'Bool' is not convertible to 'String'. Тем не менее, это работает:

let definitelyStrings = grabBag.filter{ $0 is String }   // 2 
let strings = definitelyStrings as! [String]     // 

Почему 2 работу, когда 1 не делает? И есть ли более простой способ (2) извлечения и отливки элементов [AnyObject] на все, что [T]?

+0

В примере 2 вам не нужна вторая строка: 'let strings = grabBag.filter {$ 0 is String}' достаточно. Нет принудительного литья. Докажите это с помощью 'stringings is [String]', который возвращает true – vadian

+2

@vadian 'let strings = grabBag.filter {$ 0 is String}' возвращает '[AnyObject]' с массивом 'grabBag' OP, а не' [String] '. – Moritz

+0

@EricD: Но вы можете сделать 'grabBag.filter {$ 0 is String} .map {$ 0.lowercaseString}', который обычно невозможен с '[AnyObject]' – vadian

ответ

15

Это лучше использовать flatMap для хорошего однострочного покрытия:

let strings = grabBag.flatMap { $0 as? String } 

В настоящее время strings имеет тип [String].

6

Это то, что flatMap для:

let strings = grabBag.flatMap{ $0 as? String } 

Это происходит замыкание, которое возвращает необязательный; если необязательный параметр не равен нулю, то он добавляется к результату.

( Обратите внимание, что это не соответствует значению flatMap от других языков, и даже не соответствует другому смыслу flatMap в Swift. Лучше было бы использовать название mapOptional или mapSome. Но это все-таки вида интуитивно понятный, даже если он несовместим. Он «сопоставляется с опционами, затем выравнивает все нули». Роб Майофф отмечает, что если бы Optionals были SequenceTypes, которые, вероятно, должны были быть, это было бы разумное имя.)

+1

«flatMap» Scala работает с «Option» так же, как «FlatMap» Swift работает с его «Необязательным». Но Scala получает его «бесплатно», потому что «Option» Scala - это полный тип обходной коллекции (содержащий 0 или 1 элемент). К сожалению, «Необязательный» Swift не соответствует (в настоящее время) «SequenceType». –

+0

@robmayoff Я неправильно понял подпись Scala. Это 'flatMap [B] (f: (A) ⇒ GenTraversableOnce [B]): List [B]'. Я думал, что это «flatMap [B] (f: (A) ⇒ List [List [B]]): List [B]'. ОК; Я куплю это. –

3

Я бы сказал, что ошибка теста 1 явно является ошибкой компилятора. На самом деле он выходит из строя в РЕПЛ:

Welcome to Apple Swift version 2.0 (700.1.100.2 700.1.74). Type :help for assistance. 
    1> import Foundation 
    2> let grabBag: [AnyObject] = [ "Tom", 4, "Dick", NSObject(), "Harry" ] 
grabBag: [AnyObject] = 5 values { 
    [0] = "Tom" 
    [1] = Int64(4) 
    [2] = "Dick" 
    [3] = { 
    isa = NSObject 
    } 
    [4] = "Harry" 
} 
    3> let strings = grabBag.filter { $0 is String } as! String 
strings: String = { 
    _core = { 
    _baseAddress = 
    _countAndFlags = 
    _owner = <extracting data from value failed> 

    } 
} 
Execution interrupted. Enter Swift code to recover and continue. 
Enter LLDB commands to investigate (type :help for assistance.) 
4> :bt 
* thread #1: tid = 0x501bac, 0x00000001005c41f4 $__lldb_expr12`main + 420 at repl.swift:3, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) 
    * frame #0: 0x00000001005c41f4 $__lldb_expr12`main + 420 at repl.swift:3 
    frame #1: 0x0000000100001420 repl_swift`_mh_execute_header + 5152 
    frame #2: 0x00007fff8dd725c9 libdyld.dylib`start + 1 
    frame #3: 0x00007fff8dd725c9 libdyld.dylib`start + 1 

Во всяком случае, так как Роб Napier также ответил, grabBag.flatMap { $0 as? String } короче и может быть проще.

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