#swift #protocols
#swift #протоколы
Вопрос:
У меня есть код (swift 4.2.1, xcode 10.1), который выдает ошибку компиляции «конфликтующее соответствие».
Как это следует переписать, каковы наилучшие методы для выполнения такой вещи?
Код должен поддерживать фильтрацию массивов строк или сложных объектов с использованием текстового поиска…
protocol FilterableByText{
func filter<T: StringProtocol>(by text:T) -> Self
var isEmpty:Bool {get}
}
protocol ContainsString{
func contains<T>(_ substring: T) -> Bool where T : StringProtocol
}
extension Array: FilterableByText where Element:ContainsString{
func filter<T: StringProtocol>(by text:T) -> Array{
return filter{$0.contains(text)}
}
}
extension Array: FilterableByText where Element:FilterableByText{ // conflicting conformance
func filter<T: StringProtocol>(by text:T) -> Array{
return map{$0.filter(by: text)}.filter{!$0.isEmpty}
}
}
Ответ №1:
Вместо того, чтобы пытаться создавать отдельные соответствия, что вы можете сделать, так это создать отдельные реализации нужной вам функции с разными ограничениями.
protocol ContainsString {
func contains<T>(_ substring: T) -> Bool where T: StringProtocol
}
extension Collection {
func filter<T>(by text: T) -> [Element] where T: StringProtocol, Element: ContainsString {
return filter { $0.contains(text) }
}
func filter<T>(by text: T) -> [Element] where T: StringProtocol, Element: Collection, Element.Element: ContainsString {
return filter { !$0.filter(by: text).isEmpty }
}
}
extension String: ContainsString {}
let strings = ["hello", "world"]
strings.filter(by: "hello") // ["hello"]
let stringOfStrings = [strings, ["foo", "bar"]]
stringOfStrings.filter(by: "hello") // ["hello", "world"]
Комментарии:
1. 1, это интересно. Все еще не подходит для моего варианта использования, возможно, я захочу обновить вопрос. Мне нужен был какой-нибудь протокол FilterableByText для использования в другом общем протоколе с ‘associatedtype Model: FilterableByText’, чтобы я мог компилировать выражения типа ‘NewModel = model.filter(by: searchString)’. Есть ли у вас какие-либо предложения по этому варианту использования? Вы также пропустили определение var isEmpty.
2. Мое решение расширяет
Collection
, которое уже являетсяisEmpty
свойством.3. Немного сложно понять ваш вариант использования. Если вы обновите вопрос более конкретным примером, вам будет легче помочь его смоделировать.
Ответ №2:
Как предполагает компилятор, конфликтующее соответствие неприемлемо — поведение будет неопределенным, поскольку не существует правил для разрешения конфликтующих сигнатур функций в расширениях. Что касается лучших практик, я бы посоветовал ввести более общий, но единый протокол для элементов, чтобы это не заставляло вас разделять логику в расширении по умолчанию:
Комментарии:
1. Да, очевидно, но … не могли бы вы предложить что-нибудь более конкретное?