Использование некоторого протокола в качестве конкретного типа, соответствующего другому протоколу, не поддерживается
Я пытаюсь смешивать дженерики с протоколами, и я получаю действительно трудное время 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 ответ:
основная причина ограничения заключается в том, что 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> }
если это создает проблему, вам нужно будет создать окно. Смотрите протокол не соответствует самому себе? для обсуждения того, как вы печатаете-стереть, так что вы можете держать абстрактные типы. Но вам нужно работать в конкретных типах. Вы не можете в конечном счете специализироваться на протоколе. Вы в большинстве случаев приходится специализироваться на чем-то конкретном.