У меня есть протокол со статическим методом с параметром по умолчанию. Я хочу изменить значение по умолчанию в классе, реализующем протокол. По сути дела, то, что легко сделать с классами и super.
У меня есть решение только тогда, когда протокол не имеет связанного типа.
Следующий код работает, но как только вы раскомментируете объявление связанного типа, он не скомпилируется.
protocol Protocol {
// associatedtype AssociatedType
}
extension Protocol {
func sayHello(name: String = "World") {
print("Hello, \(name)!")
}
}
class Class<T>: Protocol {
typealias AssociatedType = T
func sayHello(name: String = "Stack Overflow") {
// Uncommenting the Protocol.AssociatedType causes:
// Protocol can only be used as a generic constraint because it has associated type requirements
(self as Protocol).sayHello(name)
}
}
Class<()>().sayHello()
Я понимаю, почему он не компилируется: Protocol
не имеет конкретного типа для AssociatedType
.
Так что, возможно, вопрос следует читать «Могу ли я явно специализировать протокол?», на что я полагаю, что ответ отрицательный.
У меня есть частичное обходное решение. Но даже когда это работает, это отстой.
Особенно, если учесть, что я пишу библиотеку, в которой sayHello
является общедоступной, поэтому следующий обходной путь вынуждает меня иметь второй протокол, который должен быть общедоступным, но бесполезен.
Вот обходной путь:
protocol Parent {}
protocol Protocol: Parent {
associatedtype AssociatedType
}
extension Parent {
func sayHello(name: String = "World") {
print("Hello, \(name)!")
}
}
class Class<T>: Protocol {
typealias AssociatedType = T
func sayHello(name: String = "Stack Overflow") {
(self as Parent).sayHello(name)
}
}
Class<()>().sayHello()
Но это не работает для меня, потому что мой sayHello
использует связанный тип. Поэтому его нельзя извлечь в другой протокол.
Просто чтобы быть уверенным, что я ясно, вот что я хотел бы, только заменив класс на протокол:
class Protocol<T> {
func sayHello(name: String = "World") {
print("Hello, \(name)!")
}
}
class Class<T>: Protocol<T> {
override func sayHello(name: String = "Stack Overflow") {
super.sayHello(name)
}
}
Class<()>().sayHello()