具有约束关联类型错误 "Type is not convertible"的 Swift 协议(protocol)

标签 swift generics protocols swift2 associated-types

我已经创建了 2 个具有关联类型的协议(protocol)。符合 Reader 的类型应该能够生成符合 Value 的类型的实例。

复杂层来自符合 Manager 的类型应该能够生成具体的 Reader 实例,该实例生成特定类型的 Value(Value1Value2)。

在我对 Manager1 的具体实现中,我希望它始终生成 Reader1,后者又生成 Value1 的实例。

谁能解释一下原因

"Reader1 is not convertible to ManagedReaderType?"

当错误行更改为(暂时)返回 nil 时,所有编译都很好,但现在我无法实例化 Reader1Reader2

可以将以下内容粘贴到 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

最佳答案

错误发生是因为 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

如果您返回 nil,它可以转换为任何可选类型,因此它始终有效。

作为替代方案,您可以返回特定类型的 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()
    }
}

由于缺少“真正的”泛型(以下尚不支持),这是使用协议(protocol)的最佳方法:

// 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()
    }
}

因此,最好的解决方法是将 Reader 设为泛型类,将 Reader1Reader2 设为其特定泛型的子类:

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?

这个实现应该可以解决你的问题,但是 Readers 现在是引用类型,应该考虑复制函数。

关于具有约束关联类型错误 "Type is not convertible"的 Swift 协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31766454/

相关文章:

swift - 使用 ANY 和 AND 过滤 Realm 结果

swift - 确定字符串是否包含 Swift 集合中的字符的最佳方法是什么

swift - 如何将 UISearchController 与 SwiftUI 集成

javascript - 任意泛型的 typescript map

java - 抽象方法中的通用列表

java - 泛型友好的类型处理程序映射

protocols - 'distributed tracker' 概念在 Bittorrent DHT 中如何运作?

swift - 我可以在协议(protocol)中有一个初始化函数吗?

swift - 如何使用Swinject注册符合ObservableObject的协议(protocol)?

swift - Xib 文件在被我的页面 View Controller 调用时呈现,但不作为选项卡呈现