问题描述
在我的快速项目中,有一种情况,我使用协议继承如下
In my swift project I have a case where I use protocol inheritance as follow
protocol A : class{
}
protocol B : A{
}
我接下来要实现的是声明另一个具有关联类型的协议,该类型必须从协议A
继承.如果我尝试将其声明为:
What Im trying to achieve next is declaring another protocol with associated type, a type which must inherit from protocol A
. If I try to declare it as :
protocol AnotherProtocol{
associatedtype Type : A
weak var type : Type?{get set}
}
它编译没有错误,但是在以下情况下尝试采用AnotherProtocol
时:
it compiles without errors but when trying to adopt AnotherProtocol
in the following scenario:
class SomeClass : AnotherProtocol{
typealias Type = B
weak var type : Type?
}
编译失败,并显示错误消息,指出SomeClass
不符合AnotherProtocol
.如果我正确理解这一点,则意味着B
我试图声明并询问您如何声明从协议A
继承的关联类型时,我没有采用A
?
compilation fails with error claiming that SomeClass
does not conform to AnotherProtocol
. If I understood this correctly it means that B
does not adopt A
while Im trying to declare and asking you on how to declare an associated type which inherits from protocol A
?
我基于以下情况进行编译的事实做出了上述假设
I made the above assumption based on fact that the following scenario compiles just fine
class SomeDummyClass : B{
}
class SomeClass : AnotherProtocol{
typealias Type = SomeDummyClass
weak var type : Type?
}
推荐答案
这很有趣. 似乎,一旦您在给定协议中限制了associatedtype
的类型,就需要在该协议的实现中提供一个具体的类型(而不是另一种协议类型)–这就是为什么您的第二个例子奏效了.
This is pretty interesting. It appears that once you constrain the type of an associatedtype
in a given protocol, you need to provide a concrete type in the implementation of that protocol (instead of another protocol type) – which is why your second example worked.
如果删除关联类型上的A
约束,则第一个示例将起作用(减去关于无法在非类类型上使用weak
的错误,但这似乎无关).
If you remove the A
constraint on the associated type, your first example will work (minus the error about not being able to use weak
on a non-class type, but that doesn’t seem to be related).
说了这么多,我似乎找不到任何文档来证实这一点.如果有人能找到可以支持(或完全反对)的东西,我很想知道!
That all being said, I can't seem to find any documentation in order to corroborate this. If anyone can find something to back this up with (or completely dispute it), I’d love to know!
要使当前代码正常工作,可以使用泛型.实际上,这将用一块石头杀死两只鸟,因为现在您的代码都将被编译,并且您将从仿制药带来的类型安全性的提高中受益(通过推断您传递给它们的类型).
To get your current code working, you can use generics. This will actually kill two birds with one stone, as both your code will now compile and you'll benefit from the increased type safety that generics bring (by inferring the type you pass to them).
例如:
protocol A : class {}
protocol B : A {}
protocol AnotherProtocol{
associatedtype Type : A
weak var type : Type? {get set}
}
class SomeClass<T:B> : AnotherProtocol {
typealias Type = T
weak var type : Type?
}
编辑:由于您要避免使用具体类型,因此上述解决方案在您的特定情况下似乎无法使用.我会把它留在这里,以防它对其他人有用.
It appears the above solution won't work in your particular case, as you want to avoid using concrete types. I'll leave it here in case it's useful for anyone else.
在您的特定情况下,您可能可以使用类型擦除来为您的B
协议创建伪具体类型. 罗布·纳皮尔(Rob Napier)有一篇很棒的文章有关类型擦除.
In your specific case, you may be able to use a type erasure in order to create a pseudo concrete type for your B
protocol. Rob Napier has a great article about type erasures.
在这种情况下,这是一个很奇怪的解决方案(因为类型擦除通常用于包装associatedtypes
的协议),而且绝对不如上述解决方案那么受欢迎,因为您必须重新实现'proxy '方法,用于A
& B
协议–但它应该对您有用.
It's a bit of a weird solution in this case (as type erasures are normally used to wrap protocols with associatedtypes
), and it's also definitely less preferred than the above solution, as you have to re-implement a 'proxy' method for each method in your A
& B
protocols – but it should work for you.
例如:
protocol A:class {
func doSomethingInA() -> String
}
protocol B : A {
func doSomethingInB(foo:Int)
func doSomethingElseInB(foo:Int)->Int
}
// a pseudo concrete type to wrap a class that conforms to B,
// by storing the methods that it implements.
class AnyB:B {
// proxy method storage
private let _doSomethingInA:(Void)->String
private let _doSomethingInB:(Int)->Void
private let _doSomethingElseInB:(Int)->Int
// initialise proxy methods
init<Base:B>(_ base:Base) {
_doSomethingInA = base.doSomethingInA
_doSomethingInB = base.doSomethingInB
_doSomethingElseInB = base.doSomethingElseInB
}
// implement the proxy methods
func doSomethingInA() -> String {return _doSomethingInA()}
func doSomethingInB(foo: Int) {_doSomethingInB(foo)}
func doSomethingElseInB(foo: Int) -> Int {return _doSomethingElseInB(foo)}
}
protocol AnotherProtocol{
associatedtype Type:A
weak var type : Type? {get set}
}
class SomeClass : AnotherProtocol {
typealias Type = AnyB
weak var type : Type?
}
class AType:B {
// implement the methods here..
}
class AnotherType:B {
// implement the methods here..
}
// your SomeClass instance
let c = SomeClass()
// set it to an AType instance
c.type = AnyB(AType())
// set it to an AnotherType instance
c.type = AnyB(AnotherType())
// call your methods like normal
c.type?.doSomethingInA()
c.type?.doSomethingInB(5)
c.type?.doSomethingElseInB(4)
现在,您可以使用AnyB
类型来代替B
协议类型,而不必对其进行任何类型的限制.
You can now use the AnyB
type in place of using the B
protocol type, without making it any more type restrictive.
这篇关于如何使协议关联类型需要协议继承而不是协议采用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!