Принудительно реализовать объекты Сопоставимость с протоколом дает протокол может использоваться только как общее ограничение c - PullRequest
2 голосов
/ 10 июля 2020

У меня есть массив объектов. Теперь я хочу заставить эти объекты реализовывать Comparable.

Итак, я создал такой протокол:

protocol Foo: Comparable { }

Все идет нормально, кроме случаев, когда я создаю массив:

let array: [Foo] = [obj1, ..]

Затем компилятор вдруг жалуется:

Protocol 'Foo' can only be used as a generic constraint because it has Self or associated type требования

Есть ли другой способ сделать это?

EDIT

class View: UIView {
    let viewModel: SomeViewModel
}

class SomeViewModel {
     let views: [UIView]
}

1 Ответ

1 голос
/ 10 июля 2020

Обычно, когда люди добавляют это соответствие, они пытаются сделать что-то вроде сортировки [Foo] или найти минимальное значение, но это не сработает, даже если вы могли бы создать этот массив, потому что Comparable требует, чтобы тип быть сопоставимым со своим собственным типом , а не с другими, соответствующими протоколу. Так, например, учитывая ваш array, вы не можете использовать array.min() для поиска минимального элемента, потому что Comparable не требует, чтобы Foo было сопоставимо с Foo, только то, что соответствует Foo, можно сравнить с

Вместо этого вам нужно расширить протокол, чтобы требовать, чтобы соответствующие типы могли сравнивать себя с любыми Foo:

protocol Foo: Comparable { 
    // ... existing requirements

    func isEqual(to: Foo) -> Bool
    func isLessThan(_: Foo) -> Bool
}

Учитывая это, вы можете создавать любые другие алгоритмы, которые вам нужны. Вы не можете использовать формы по умолчанию contains или sorted, но вы можете использовать эти функции в параметрах where и by.

Вы также можете сделать это немного лучше, предоставив некоторые реализации по умолчанию:

extension Foo where Self: Equatable {
    func isEqual(to other: Foo) -> Bool {
        guard let other = other as? Self else {
            return false
        }
        return self == other
    }
}

И аналогично для isLessThan.

И если вам нужны такие вещи, как contains, вы также можете предоставить помощников, если это удобно:

extension Sequence where Element == Foo {
    func contains(_ element: Element) -> Bool {
        return contains(where: { $0.isEqual(to: element) })
    }
}

Если вам нужна более длинная версия этого обсуждения, см. Generi c Swift: это не должно причинить вреда . Эта конкретная тема возникает в 37:40.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...