Протокол Swift форсирует протокол Equatable

Я определил 2 протокола. Мне нужен первый (NameProtocol) для обеспечения соблюдения протокола Equatable. В то время как другой класс (BuilderProtocol) имеет метод, возвращающий первый (NameProtocol).

public protocol NameProtocol : Equatable {
    var name: String { get }
}

public protocol BuilderProtocol {
    func build() -> NameProtocol? // Compiler error
    init()
}

Ошибка компилятора: «Протокол« NameProtocol »может использоваться только в качестве общего ограничения, поскольку он имеет требования типа Self или связанные с ним».

Мне нужен объект, возвращаемый функцией build (), чтобы вернуть объект, соответствующий NameProtocol и для которого я могу определить ==

Есть ли способ заставить эту работу работать?

Спасибо


При использовании псевдонима типа в BuilderProtocol, как я могу заставить работать объявление массива?

public protocol OtherRelatedProtocol {
    var allNames : Array<NameProtocol> { get }
}

Заключение

Я удалю Equatable и реализую метод isEqual.

public protocol NameProtocol {
    func isEqual(nameable: NameProtocol) -> Bool
    var name: String { get }
}

person Vincent Bernier    schedule 24.04.2015    source источник
comment
Это сообщение об ошибке вводит в заблуждение (все еще в версии 3.0.2); он должен читать если есть.   -  person Raphael    schedule 14.02.2017


Ответы (1)


Если вы знакомы с Java или C #, протоколы Swift находятся примерно на полпути между универсальными шаблонами и интерфейсами. Например, в протоколе можно сделать следующее:

protocol Foo {
    func compareWith(foo: Self)
}

Классы, реализующие этот протокол, будут иметь метод compareWith, который принимает объект своего собственного типа (а не объект типа Foo).

Это то, что компилятор называет «Собственные или связанные требования типа», и именно так определяется Equatable (ему нужен operator==, который принимает два Self операнда). Однако обратная сторона этих протоколов заключается в том, что вы можете использовать их только как общие ограничения: вы не можете использовать их как тип выражения.

Решение - использовать дженерики. В этом случае вы должны сделать свой ProtocolBuilder протокол общим с ограничением, которое этот тип реализует NameProtocol.

public protocol NameProtocol : Equatable {
    var name: String { get }
}

public protocol BuilderProtocol {
    typealias T: NameProtocol
    func build() -> T?
    init()
}
person zneak    schedule 24.04.2015
comment
Что не будет компилироваться, потому что это не то, как вы делаете общий протокол. - person matt; 24.04.2015
comment
Да, Мэтт, я должен был это проверить. - person zneak; 24.04.2015
comment
Особенно, если вы просто собираетесь сказать то, что я уже сказал в своем комментарии. :) - person matt; 24.04.2015
comment
О, нет! Хорошо, тогда я удаляю свой комментарий и свой ответ. Драт. - person matt; 24.04.2015
comment
Нет, моя беда, я не умею считать и мне нужно спать. Вы были там первыми. - person zneak; 24.04.2015
comment
спасибо, вариант 2 оставляет меня с другой проблемой, я обновлю вопрос, чтобы показать это. - person Vincent Bernier; 24.04.2015
comment
@VinceBurn, требования к ассоциированному типу в протоколах довольно вирусны. Вы можете подумать о перегрузке протоколов == и != без соответствия Equatable или сделать так, чтобы ваши классы соответствовали ему отдельно от NameProtocol, если вы не можете распространять дженерики через весь код. - person zneak; 24.04.2015
comment
@zneak моя цель - создать фреймворк, который выделяет объект, но я хочу, чтобы внешний мир знал только о протоколах, потому что точные классы могут измениться, или в этом случае протокол может поддерживаться структурой. Но моя цель - сохранить детали реализации внутри фреймворка и обеспечить максимальную гибкость, которую я могу получить. - person Vincent Bernier; 24.04.2015
comment
@VinceBurn, я не думаю, что смогу вам с этим помочь. Я бы, наверное, остановился на базовом классе. Вы уверены, что вам нужна гибкость возврата структуры вместо класса? Протоколы Swift не скрывают скрытую природу структурных значений, поэтому мне это кажется плохой идеей. - person zneak; 24.04.2015
comment
Возможно, я бы обновил структуру до класса, но только неизменяемого объекта. - person Vincent Bernier; 24.04.2015