具有约束关联类型错误的Swift协议“类型不可转换”

时间:2023-01-23 22:20:00

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.

我创建了2个具有相关类型的协议。符合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

1 个解决方案

#1


3  

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:

发生此错误是因为read函数中的ManagerReaderType只是符合Reader且其ReaderValueType等于ManagerReaderType的任何类型的通用占位符。因此,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.

此实现应该可以解决您的问题,但读者现在是引用类型,应该考虑复制函数。

#1


3  

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:

发生此错误是因为read函数中的ManagerReaderType只是符合Reader且其ReaderValueType等于ManagerReaderType的任何类型的通用占位符。因此,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.

此实现应该可以解决您的问题,但读者现在是引用类型,应该考虑复制函数。