Подтвердить что ты не робот

Использование некоторого протокола как конкретного типа, соответствующего другому протоколу, не поддерживается

Я пытаюсь смешивать генераторы с протоколами, а Im получает очень тяжелое время xD

У меня есть определенная архитектура, реализованная в проекте Android/Java, и я пытаюсь переписать ее, чтобы соответствовать ей в проекте swift/iOS. Но я нашел это ограничение.

ProtocolA

protocol ProtocolA {

}

ProtocolB

protocol ProtocolB : ProtocolA {

}

ImplementProtocolA

class ImplementProtocolA <P : ProtocolA> {

    let currentProtocol : P

    init(currentProtocol : P) {
        self.currentProtocol = currentProtocol
    }

}

ImplementProtocolB

class ImplementProtocolB : ImplementProtocolA<ProtocolB> {

}

Итак, когда я пытаюсь установить ProtocolB как конкретный тип, реализующий ProtocolA, я получаю эту ошибку:

Использование "ProtocolB" как конкретного типа, соответствующего протоколу "ProtocolA", не поддерживается

1 Есть ли причина для этого "ограничения"?

2 Есть ли какое-либо обходное решение для его реализации?

3 Будет ли она поддерживаться в какой-то момент?

- ОБНОВЛЕНО -

Другой вариант той же проблемы, я думаю:

Просмотр протоколов

protocol View {

}

protocol GetUserView : View {
    func showProgress()
    func hideProgress()
    func showError(message:String)
    func showUser(userDemo:UserDemo)
}

Протоколы презентатора

protocol Presenter {
    typealias V : View
}

class UserDemoPresenter : Presenter {
    typealias V = GetUserView
}

Ошибка:

UserDemoPresenter.swift Возможно, это соответствует 'V' (aka "GetUserView" ) не соответствует "View

Что это? Он соответствует!

Даже если я использую View вместо GetUserView, он не компилируется.

class UserDemoPresenter : Presenter {
    typealias V = View
}

UserDemoPresenter.swift Возможное соответствие 'V' (aka 'View') не соответствует "View"

xxDD Я действительно не понимаю.

- ОБНОВЛЕНО -

С решением, предложенным Роба Напиром, проблема не исправлена, вместо этого она просто задерживается.

Когда вы пытаетесь определить ссылку на UserDemoPresenter, мне нужно указать общий тип, поэтому я получаю ту же ошибку:

private var presenter : UserDemoPresenter<GetUserView>

Использование GetUserView в качестве конкретного типа, соответствующего протоколу "GetUserView" не поддерживается

4b9b3361

Ответ 1

Основная причина ограничения заключается в том, что Swift не имеет первоклассных метатипов. Самый простой пример - это не работает:

func isEmpty(xs: Array) -> Bool {
    return xs.count == 0
}

В теории, этот код мог бы работать, и если бы это было сделано, было бы много других типов, которые я мог бы сделать (например, Functor и Monad, которые действительно не могут быть выражены в Swift сегодня). Но вы не можете. Вам нужно помочь Swift прибить это к конкретному типу. Часто мы делаем это с помощью дженериков:

func isEmpty<T>(xs: [T]) -> Bool {
    return xs.count == 0
}

Обратите внимание, что T здесь полностью избыточно. Нет причин, по которым я должен был бы это выразить; он никогда не использовался. Но Свифт требует его, чтобы он мог превратить абстрактный Array в конкретный [T]. То же самое верно и в вашем случае.

Это конкретный тип (ну, это абстрактный тип, который будет превращаться в конкретный тип при его создании и P):

class ImplementProtocolA<P : ProtocolA>

Это полностью абстрактный тип, в котором Swift не имеет никакого правила превращаться в конкретный тип:

class ImplementProtocolB : ImplementProtocolA<ProtocolB>

Вам нужно сделать это конкретным. Это скомпилирует:

class ImplementProtocolB<T: ProtocolB> : ImplementProtocolA<T> {}

А также:

class UserDemoPresenter<T: GetUserView> : Presenter {
    typealias V = T
}

Просто потому, что вы, вероятно, столкнетесь с проблемой позже: ваша жизнь будет намного проще, если вы создадите эти структуры или классы final. Протоколы микширования, дженерики и полиморфизм классов полны очень острыми краями. Иногда вам повезло, и он просто не компилируется. Иногда он будет называть то, чего вы не ожидаете.

Возможно, вас заинтересует Маленький респект для AnySequence, в котором подробно описаны некоторые связанные с этим проблемы.


private var presenter : UserDemoPresenter<GetUserView>

Это еще абстрактный тип. Вы имеете в виду:

final class Something<T: GetUserView> {
    private var presenter: UserDemoPresenter<T>
}

Если это создает проблему, вам нужно создать поле. См. Протокол не соответствует самому себе? для обсуждения того, как вы стираете тип, чтобы вы могли использовать абстрактные типы. Но вам нужно работать в конкретных типах. Вы не можете в конечном счете специализироваться на протоколе. В большинстве случаев вы должны специализироваться на чем-то конкретном.