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


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

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

Протоколома

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 как конкретный тип, реализующий Протоколома, я получаю эту ошибку:

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

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.Свифт, возможно, предназначались матч " в " (он же 'GetUserView') не соответствует 'View'

что это?? Это соответствует!

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

class UserDemoPresenter : Presenter {
    typealias V = View
}

UserDemoPresenter.swift, возможно, предназначенный матч " V "(он же "вид") делает не соответствует "взгляду"

xxDD я не понимаю, на самом деле.

--обновление--

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

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

private var presenter : UserDemoPresenter<GetUserView>

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

1 52

1 ответ:

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

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

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

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

обратите внимание, что T здесь совершенно излишним. Нет никакой причины, по которой я должен был бы выразить это; это никогда не использовалось. Но Swift требует этого, чтобы он мог превратить абстрактное 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 классы. Протоколы смешивания, дженерики и полиморфизм классов полны очень острых краев. Иногда вам повезло, и он просто не будет компилироваться. Иногда он будет называть вещи, которые вы не ожидаете.

вы может заинтересовать немного уважения к любой последовательности какие детали некоторые связанные вопросы.


private var presenter : UserDemoPresenter<GetUserView>

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

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

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