如何制作动态的泛型?

时间:2019-07-15 11:42:17

标签: swift generics protocols

我正在尝试编写一个协议,允许我在应用程序中对模型进行版本控制。为此,我编写了以下VersionManager

class VersionManager<Type: Decodable> {
    private var database: Database

    init(database: Database) {
        self.database = database
    }

    var versions: [Type] {
        return []
    }
}

之后,我编写了可以添加到模型中的协议:

protocol Versionable {

}

extension Versionable {
    private var manager: VersionManager<Restaurant> {
        return VersionManager<Restaurant>(database: Database.shared)
    }

    public var versions: [Restaurant] {
        return manager.versions
    }
}

现在,我面临的问题是我尝试动态传递类型,而不是像现在对Restaurant那样进行硬编码。

所以我尝试将协议更改为此:

protocol Versionable {
    var kind: Decodable.Type { get }
}

然后我想将kind传递给VersionManager。但是,当我尝试Xcode引发此错误时:Expected '>' to complete generic argument list

还有其他方法吗?

1 个答案:

答案 0 :(得分:1)

如果要在protocol内使用泛型,则需要使用associatedtype

protocol Versionable {
    associatedtype Model: Decodable
}

extension Versionable {
    private var manager: VersionManager<Model> {
        return VersionManager<Model>(database: Database.shared)
    }

    public var versions: [Model] {
        return manager.versions
    }
}

将要实现Versionable协议的模型必须解决此类型:

struct SomeModel: Versionable {
    typealias Model = Int
}

SomeModel().versions // [Int]

我猜您的示例中的Restaurant是指实现Versionable的模型。在这种情况下,您只需在协议扩展内使用Self引用:

protocol Versionable: Decodable {
}

extension Versionable {
    private var manager: VersionManager<Self> {
        return VersionManager<Self>(database: Database.shared)
    }

    public var versions: [Self] {
        return manager.versions
    }
}

struct SomeModel: Versionable {}
SomeModel().versions // [SomeModel]

请注意,由于Versionable的通用约束,Decodable协议现在需要VersionManager<Type: Decodable>符合性。