2016-12-08 4 views
4

Я пытаюсь создать «безопасный» оператор подписи для коллекции - тот, который игнорирует части диапазонов, выходящие за пределы доступных индексов для коллекции.Почему мое расширение протокола Swift не переносит существующую функцию того же типа?

Желаемое поведение - вернуть Slice во всех случаях; когда нет перекрытия между диапазоном индексов и диапазоном сбора, и пустой массив должен быть возвращен.

Это показалось простым расширением по технике, представленной в this answer. documentation of the collection subscript operator is very straightforward:

subscript(bounds: Range<Self.Index>) -> Slice<Self> { get } 

Но когда я принимать те же типы в моей функции-оболочки, я получаю следующее: snippet

версия Копирование/вставка:

extension Collection where Indices.Iterator.Element == Index { 
    subscript(safe bounds: Range<Self.Index>) -> Slice<Self> { 
     let empty = Slice(base: self, bounds: (startIndex..<startIndex)) 
     guard bounds.lowerBound < endIndex else { return empty } 
     guard bounds.upperBound >= startIndex else { return empty } 

     let lo = Swift.max(startIndex, bounds.lowerBound) 
     let hi = Swift.min(endIndex, bounds.upperBound) 
     return self[lo..<hi] 
    } 
} 

Почему я не могу подстрочный сборник таким образом? Почему компилятор подтверждает, что я использую правильный тип Range<Self.Index> (указанный в документации), но все еще рассматривая его как ошибку?

+0

Обратите внимание, что ограничение 'где Indices.Iterator.Element == Index' не используемый в вашем пользовательском индексе. Возможно, вам стоит рассмотреть возможность переноса его в неограниченное расширение 'Collection' (при условии, что у вас есть другие методы, которые используют ограничение в вашем текущем). – Hamish

+1

Чтобы более точно ответить на вопрос Хэмиша: 'self [lo .. ». Конечно, сообщение об ошибке (как часто) очень вводит в заблуждение. – matt

+0

@Hamish Я думаю, мне нужно это ограничение для другой функции в моем расширении ([в этом ответе] (http://stackoverflow.com/a/30593673/2063546)), но даже тогда - согласно моему комментарию там - я не понимаю его построения. – Ian

ответ

4

The ranged subscript requirement of Collection возвращает SubSequence (ассоциированный тип):

subscript(bounds: Range<Self.Index>) -> Self.SubSequence { get } 

subscript that you refer to:

subscript(bounds: Range<Self.Index>) -> Slice<Self> { get } 

только реализацияпо умолчанию этого индекса, где SubSequence является Slice<Self>. Любой тип, соответствующий Collection, может реализовать это требование по-разному - они не обязательно должны определять их SubSequence как Slice<Self>.

Поэтому вам нужно просто изменить расширение, чтобы отразить, что SubSequence возвращается из подстрочных вы используете:

extension Collection { 
    subscript(safe bounds: Range<Index>) -> SubSequence { 

     // as the method returns a SubSequence, 
     // use the regular subscript to get an empty SubSequence 
     let empty = self[startIndex..<startIndex] 

     guard bounds.lowerBound < endIndex else { return empty } 
     guard bounds.upperBound >= startIndex else { return empty } 

     let lo = Swift.max(startIndex, bounds.lowerBound) 
     let hi = Swift.min(endIndex, bounds.upperBound) 

     return self[lo..<hi] 
    } 
} 
+0

Итак, если я правильно понимаю это, ошибка компилятора отражает идею о том, что возвращение «Slice » не произойдет с операцией «индекс», которую я пытаюсь сделать? – Ian

+0

@Ian Да, ошибка компилятора говорит вам (довольно плохо), что он не может найти требование 'subscript' в протоколе' Collection', который возвращает 'Slice ', поскольку требование в протоколе возвращает ' SubSequence', а не 'Slice '. – Hamish

+0

Несмотря на то, что для требования к индексам используется реализация по умолчанию, которая возвращает «Slice », компилятор не может гарантировать, что он существует для любой коллекции (вы могли бы, конечно, ограничить расширение, чтобы «SubSequence' * 'Slice ', который позволит вашему текущему коду работать, но я не вижу практической причины для введения этого ограничения). – Hamish