2016-09-15 3 views
4

мне нужно сделать что-то вроде этого:Swift3: тип логического вывода внутри общего расширения

extension Array { 
    func flat() -> Element { return self.flatMap { $0 } } 
} 

Но есть проблема с выводом типа:

'flatMap' производит «[SegmentOfResult.Iterator.Element ]», а не предполагаемого типа контекстной результат 'Элемент'

Edit: экс использования mple:

[[1,2],[3,4,5],[6]].flat() 

следует производить [1,2,3,4,5,6] что то же самое, как:

[[1,2],[3,4,5],[6]].flatMap { $0 } 
+4

Какова цель этой функции? Каким должен быть результат '[1, 2, 3] .flat()'? –

+0

@MartinR исправлено. – marek094

ответ

4

Если вы посмотрите на flatMap(_:) подписи,

extension Sequence { 
    // ... 
    public func flatMap<SegmentOfResult : Sequence>(_ transform: (Self.Iterator.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Iterator.Element] 
    // ... 
} 

вы увидите, что она возвращает [SegmentOfResult.Iterator.Element], где SegmentOfResult - это тип, возвращаемый функцией, которую вы передаете. Это не обязательно тот же тип, что и Element (в качестве расширения для все массивов), поэтому ваш код не удается скомпилировать.

Для того, чтобы работать с массивами, где элементы являются последовательностями, вы хотите ограничить расширение, чтобы Element : Sequence.

Кроме того, поскольку функция, которую вы передаете в flatMap(_:), является преобразованием идентичности (она просто возвращает элемент, который он получает как вход), вы хотите изменить тип возврата на [Element.Iterator.Element] (массив внутреннего элемента) ,

extension Array where Element : Sequence { 
    func flat() -> [Element.Iterator.Element] { 
     return self.flatMap { $0 } 
    } 
} 

Хотя, как говорится, я не вижу причин, почему это не должно быть продолжением Sequence:

// An extension for a sequence of sequences 
extension Sequence where Iterator.Element : Sequence { 

    // returns an array of the inner element type (an array of the element of the element) 
    func flat() -> [Iterator.Element.Iterator.Element] { 
     return self.flatMap { $0 } 
    } 
} 

(Тем не менее, я не вижу необходимости, чтобы создать расширение для это в первую очередь - array.flatMap{$0} не совсем длинный!)

+1

W.r.t. последний абзац: или, как другая родная альтернатива (как обсуждалось ранее в потоке, я не могу найти сейчас :), 'Array (array.joined())'. Ninja-edit: как описано в [this Q & A] (http://stackoverflow.com/questions/39115192). – dfri

+0

И что, если я хотел бы использовать 'extension Array где Element: Array'? – marek094

+2

@ marek094 'Array' не протокол - так что это невозможно (вы не можете соответствовать конкретному типу). То, что вы ищете, - это 'расширение Array, где Element == Array', который является [конкретным требованием такого же типа] (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md # specific-same-type-requirements), которые Swift в настоящее время не поддерживает (есть решения для решения этой проблемы, связанные с протоколированием протоколами (см., например, [этот вопрос и ответы] (http://stackoverflow.com/questions/37977817/extension-for-generic-type-unsafemutablepointeruint8)), но это не совсем красиво). – Hamish