Как сделать дженерики в ограничении типа коллекции?

Я пытался извлечь ненулевые значения из массива String. Как ниже. Но мой старший хочет, чтобы он мог извлечьненулевые значения из других типов тоже.

Я читаю,дженерики может помочь мне для обработки разных типов. Как я могу использовать дженерики, чтобы я мог использовать следующее расширение как для работы с другими типами?

getNonNil должен возвращать извлеченные ненулевые значения определенного типа (т.е.если массив [String?], он должен возвращать [String], возвращает [Int], если [Int?])

Потому что я должен делать дальнейшие расчеты.

То, что я попробовал, ниже:

import Foundation
// Extended the collection-type so that collectiontype is constrained to having element with optional strings
extension CollectionType where Self.Generator.Element == Optional<String>{
    func getNonNil() -> [String] {
        // filter out all nil elements and forcefully unwrap them using map
        return self.filter({$0 != nil}).map({$0!})
    }
}

// Usage
let x: [String?] = ["Er", "Err", nil, "errr"]

x.getNonNil().forEach { (str) in
    print(str)
}

Ответы на вопрос(3)

Самый простой подход заключается в использованииflatMap какkennytm предлагается, но если вы абсолютно хотите знать, как создать такой метод с использованием обобщений, один из подходов заключается в создании глобального метода, который принимает коллекцию в качестве параметра:

public func getNonNil<T, C: CollectionType where C.Generator.Element == Optional<T>>(collection: C) -> [T] {
    return collection.filter({$0 != nil}).map({$0!})
}

let x: [String?] = ["Er", "Err", nil, "errr"]

print(getNonNil(x)) // returns ["Er", "Err", "errr"]

так как вы не можете вводить новые универсальные типы в расширения (хотя эточасть Манифеста Swift Generics - так может быть и в будущей версии Swift).

Как@kennytm говоритсамое простое решение - просто использоватьflatMap, который отфильтровываетnil:

x.flatMap{$0}.forEach { (str) in
    print(str)
}

Однако, если вы все еще хотите это как расширение, вымог используйте обходной путь протокола, чтобы позволить ограничить расширение любым дополнительным типом элемента (Swift 3):

protocol _OptionalProtocol {
    associatedtype Wrapped
    func _asOptional() -> Wrapped?
}

extension Optional : _OptionalProtocol {
    func _asOptional() -> Wrapped? {return self}
}

extension Collection where Self.Iterator.Element : _OptionalProtocol {
    func getNonNil() -> [Iterator.Element.Wrapped] {
        return flatMap{$0._asOptional()}
    }
} 

...

let x : [String?] = ["Er", "Err", nil, "errr"]

x.getNonNil().forEach { (str) in
    print(str)
}

(В Свифте 3CollectionType был переименован вCollection, а такжеGenerator сейчасIterator)

ХотяflatMap почти наверняка предпочтительнее в этой ситуации, я только действительно добавляю это для завершения.

ЗаgetNonNil Вы могли бы просто использовать

x.flatMap { $0 }
// returns ["Er", "Err", "errr"] which is [String]

Для исходного вопроса, как правило, вы можете ввести протокол для типа Optional (например, черезmuukii / OptionalProtocol упаковка):

protocol OptionalProtocol {
    associatedtype Wrapped
    var value: Wrapped? { get }
}

extension Optional: OptionalProtocol {
    public var value: Wrapped? { return self }
}

extension CollectionType where Self.Generator.Element: OptionalProtocol {
    func getNonNil() -> [Self.Generator.Element.Wrapped] {
        ...
    }
}
 Hamish18 июл. 2016 г., 15:03
@Dari Вы бы хотели сделатьreturn flatMap {$0.value} вgetNonNil метод.
 Dari18 июл. 2016 г., 14:57
flatmap сработало. Но во втором решении, как я могу его использовать? Можете ли вы показать мне пример? Потому что, когда я попытался, я получил «фатальную ошибку: неожиданно обнаружил ноль при развертывании необязательного значения» или другую ошибку.

Ваш ответ на вопрос