具有约束关联类型错误的Swift协议“类型不可转换” [英] Swift protocol with constrained associated type error "Type is not convertible"
问题描述
我创建了2个关联类型的协议。符合 Reader
的类型应该能够生成符合 Value
的类型实例。
复杂层来自符合的类型Manager>
应该能够产生具体的 Reader
产生特定类型的
值
(或者 Value1
或者 Value2 )。
使用 Manager1
的具体实现,我希望它始终产生 Reader1
,这又产生 Value1
的实例。
有人可以解释为什么
Reader1不可转换为ManagedReaderType?
当错误行改为(现在)返回 nil
它全部编译得很好,但现在我不能实例化 Reader1
或 Reader2
。
以下内容可以粘贴到Playground中以查看错误:
import Foundation
协议值{
var value:Int {get}
}
协议读取器{
typealias ReaderValueType:Value
func value() - > ReaderValueType
协议管理器{
typealias ManagerValueType:Value
func read< ManagerReaderType:Reader其中ManagerReaderType.ReaderValueType == ManagerValueType>() - > ManagerReaderType?
$ b $ struct结构Value1:Value {
let value:Int = 1
}
struct Value2:Value {
让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其中ManagerReaderType.ReaderValueType == ManagerValueType>() - > ManagerReaderType? {
返回Reader1()//错误:Reader1不能转换为ManagedReaderType?尝试交换返回无编译的nil。
}
}
let manager = Manager1()
let v = manager.v.value
let a:Reader1? = manager.read()
.dynamicType
由于 ManagerReaderType
在 read
函数中只是任何类型的通用占位符,符合 Reader
及其 ReaderValueType
等于 ManagerReaderType
之一。因此, ManagerReaderType
的实际类型不是由函数本身决定的,而是被赋值的变量的类型声明了类型:
let manager = Manager1()
let reader1:Reader1? = manager.read()// ManagerReaderType的类型为Reader1
let reader2:Reader2? = manager.read()// ManagerReaderType的类型为Reader2
如果返回 nil
它可以转换为任何可选类型,因此它总能正常工作。
作为替代方案,您可以返回特定类型的类型 Reader
:
协议管理器{
//这与SequenceType的生成器,其元素类型为
//但它将ManagerReaderType限制为一个特定的Reader
typealias ManagerReaderType:Reader
func read() - > ManagerReaderType?
}
class Manager1:Manager {
func read() - > Reader1? {
return Reader1()
}
}
这是由于缺乏真正的泛型,协议的最佳方法(以下不支持(尚)):
pre $ //这将完全符合您的要求
协议Reader< T:Value> {
fun value() - > T
}
协议管理器< T:值> {
func read() - >读取器LT; T> ;?
}
class Manager1:Manager< Value1> {
func read() - >读取器LT;值1> ;? {
return Reader1()
}
}
最好的解决方法是使 Reader2 $ c
class Reader< T:Value> {
func value() - > T {
//或提供一个虚拟值
fatalError(实现我)
}
}
//函数的一个小改动签名
协议管理器{
typealias ManagerValueType:值
func read() - >读取器LT; ManagerValueType> ;?
}
class Reader1:Reader< Value1> {
覆盖func value() - > Value1 {
return Value1()
}
}
class Reader2:Reader< Value2> {
覆盖func value() - > Value2 {
return Value2()
}
}
class Manager1:Manager {
typealias ManagerValueType = Value1
func read() - >读取器LT; ManagerValueType> ;? {
return Reader1()
}
}
让manager = Manager1()
//你必须抛出它,否则它是类型Reader< Value1>
让a:Reader1? = manager.read()as! Reader1?
这个实现应该可以解决你的问题,但是读者
现在是引用类型,应考虑复制功能。
I have created 2 protocols with associated types. A type conforming to Reader
should be able to produce an instance of a type conforming to 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
).
With my concrete implementation of Manager1
I'd like it to always produce Reader1
which in turn produces instances of Value1
.
Could someone explain why
"Reader1 is not convertible to 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
.
The following can be pasted into a Playground to see the error:
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
. 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:
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.
As an alternative you can return a specific type of type 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:
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.
这篇关于具有约束关联类型错误的Swift协议“类型不可转换”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!