[英]Swift protocol with constrained associated type error “Type is not convertible”
I have created 2 protocols with associated types. 我创建了2个具有相关类型的协议。 A type conforming to
Reader
should be able to produce an instance of a type conforming to Value
. 符合
Reader
的类型应该能够生成符合Value
的类型的实例。
The layer of complexity comes from a type conforming to Manager
should be able to produce a concrete Reader
instance which produces a specific type of Value
(either Value1
or Value2
). 复杂层来自符合
Manager
的类型,应该能够生成一个具体的Reader
实例,它生成一个特定类型的Value
( Value1
或Value2
)。
With my concrete implementation of Manager1
I'd like it to always produce Reader1
which in turn produces instances of Value1
. 通过我对
Manager1
具体实现,我希望它始终生成Reader1
,而Reader1
又生成Value1
实例。
Could someone explain why 有人可以解释原因
"Reader1 is not convertible to ManagedReaderType?"
“Reader1无法转换为ManagedReaderType?”
When the erroneous line is changed to (for now) return nil
it all compiles just fine but now I can't instantiate either Reader1
or Reader2
. 当错误的行改为(现在)返回
nil
,所有编译都很好,但现在我无法实例化Reader1
或Reader2
。
The following can be pasted into a Playground to see the error: 可以将以下内容粘贴到Playground中以查看错误:
import Foundation
protocol Value {
var value: Int { get }
}
protocol Reader {
typealias ReaderValueType: Value
func value() -> ReaderValueType
}
protocol Manager {
typealias ManagerValueType: Value
func read<ManagerReaderType: Reader where ManagerReaderType.ReaderValueType == ManagerValueType>() -> ManagerReaderType?
}
struct Value1: Value {
let value: Int = 1
}
struct Value2: Value {
let value: Int = 2
}
struct Reader1: Reader {
func value() -> Value1 {
return Value1()
}
}
struct Reader2: Reader {
func value() -> Value2 {
return Value2()
}
}
class Manager1: Manager {
typealias ManagerValueType = Value1
let v = ManagerValueType()
func read<ManagerReaderType: Reader where ManagerReaderType.ReaderValueType == ManagerValueType>() -> ManagerReaderType? {
return Reader1()// Error: "Reader1 is not convertible to ManagedReaderType?" Try swapping to return nil which does compile.
}
}
let manager = Manager1()
let v = manager.v.value
let a: Reader1? = manager.read()
a.dynamicType
The error occurs because ManagerReaderType
in the read
function is only a generic placeholder for any type which conforms to Reader
and its ReaderValueType
is equal to the one of ManagerReaderType
. 发生此错误是因为
read
函数中的ManagerReaderType
只是符合Reader
且其ReaderValueType
等于ManagerReaderType
任何类型的通用占位符。 So the actual type of ManagerReaderType
is not determined by the function itself, instead the type of the variable which gets assigned declares the type: 因此,
ManagerReaderType
的实际类型不是由函数本身决定的,而是被赋值的变量的类型声明了类型:
let manager = Manager1()
let reader1: Reader1? = manager.read() // ManagerReaderType is of type Reader1
let reader2: Reader2? = manager.read() // ManagerReaderType is of type Reader2
if you return nil
it can be converted to any optional type so it always works. 如果你返回
nil
它可以转换为任何可选类型,所以它总是有效。
As an alternative you can return a specific type of type Reader
: 作为替代方案,您可以返回特定类型的
Reader
类型:
protocol Manager {
// this is similar to the Generator of a SequenceType which has the Element type
// but it constraints the ManagerReaderType to one specific Reader
typealias ManagerReaderType: Reader
func read() -> ManagerReaderType?
}
class Manager1: Manager {
func read() -> Reader1? {
return Reader1()
}
}
This is the best approach with protocols due to the lack of "true" generics (the following isn't supported (yet)): 由于缺少“真正的”泛型,这是使用协议的最佳方法(不支持以下内容):
// this would perfectly match your requirements
protocol Reader<T: Value> {
fun value() -> T
}
protocol Manager<T: Value> {
func read() -> Reader<T>?
}
class Manager1: Manager<Value1> {
func read() -> Reader<Value1>? {
return Reader1()
}
}
So the best workaround would be to make Reader
a generic class and Reader1
and Reader2
subclass a specific generic type of it: 所以最好的解决方法是使
Reader
成为泛型类, Reader1
和Reader2
子类是它的特定泛型类型:
class Reader<T: Value> {
func value() -> T {
// or provide a dummy value
fatalError("implement me")
}
}
// a small change in the function signature
protocol Manager {
typealias ManagerValueType: Value
func read() -> Reader<ManagerValueType>?
}
class Reader1: Reader<Value1> {
override func value() -> Value1 {
return Value1()
}
}
class Reader2: Reader<Value2> {
override func value() -> Value2 {
return Value2()
}
}
class Manager1: Manager {
typealias ManagerValueType = Value1
func read() -> Reader<ManagerValueType>? {
return Reader1()
}
}
let manager = Manager1()
// you have to cast it, otherwise it is of type Reader<Value1>
let a: Reader1? = manager.read() as! Reader1?
This implementation should solve you problem, but the Readers
are now reference types and a copy function should be considered. 此实现应该可以解决您的问题,但
Readers
现在是引用类型,应该考虑复制函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.