使用泛型将符合协议的对象和泛型存储在类型数组中 [英] Storing objects conforming to a protocol with generics in a typed array

查看:86
本文介绍了使用泛型将符合协议的对象和泛型存储在类型数组中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个协议:

protocol Adjustable: Equatable {
    associatedtype T
    var id: String { get set }
    var value: T { get set }
    init(id: String, value: T)
}

和一个符合它的结构:

struct Adjustment: Adjustable {
    static func == (lhs: Adjustment, rhs: Adjustment) -> Bool {
        return lhs.id == rhs.id
    }

    typealias T = CGFloat
    var id: String
    var value: T
}

我正在构建一个包装类,该包装类的行为类似于Set,以处理这些属性的有序列表:

And I'm building a wrapper class that behaves like a Set to handle an ordered list of these properties:

struct AdjustmentSet {
    var adjustmentSet: [Adjustable] = []
    func contains<T: Adjustable>(_ item: T) -> Bool {
        return adjustmentSet.filter({ $0.id == item.id }).first != nil
    }
}

let brightness = Adjustment(id: "Brightness", value: 0)

let set = AdjustmentSet()
print(set.contains(brightness))

但是那当然是行不通的,出现以下错误:

But that of course doesn't work, erroring with:

错误:协议可调整"只能用作一般约束,因为它具有自我"或相关联的类型要求 var AdjustmentSet:[可调] = []

error: protocol 'Adjustable' can only be used as a generic constraint because it has Self or associated type requirements var adjustmentSet: [Adjustable] = []

环顾四周,我起初以为是因为该协议不符合Equatable,但是后来我添加了它,但它仍然不起作用(或者我做错了).

Looking around, I thought at first this was because the protocol doesn't conform to Equatable, but then I added it, and it still doesn't work (or I did it wrong).

此外,我希望能够在此处使用通用名称,以便可以执行以下操作:

Moreover, I would like to be able to use a generic here, so that I can do something like:

struct Adjustment<T>: Adjustable {
    static func == (lhs: Adjustment, rhs: Adjustment) -> Bool {
        return lhs.id == rhs.id
    }

    var id: String
    var value: T
}

let brightness = Adjustment<CGFloat>(id: "Brightness", value: 0)

或者:

struct FloatAdjustment: Adjustable {
    static func == (lhs: Adjustment, rhs: Adjustment) -> Bool {
        return lhs.id == rhs.id
    }
    typealias T = CGFloat
    var id: String
    var value: T
}

let brightness = FloatAdjustment(id: "Brightness", value: 0)

并且仍然能够存储[Adjustable]类型的数组,以便最终我可以做到:

And still be able to store an array of [Adjustable] types, so that eventually I can do:

var set = AdjustmentSet()
if set.contains(.brightness) {
    // Do something!
}

var brightness = ...
brightness.value = 1.5
set.append(.brightness)

推荐答案

您不能拥有类型为Adjustable的项目数组,因为Adjustable并不是真正的类型.这是一张蓝图,描述了一组类型,每个T的可能值中的一个.

You can't have an array of items of type Adjustable, because Adjustable isn't really a type. It's a blue print that describes a set of types, one per every possible value of T.

要解决此问题,您需要使用类型橡皮擦 https://medium.com/dunnhumby-data-science-engineering/swift-associated-type-design-patterns-6c56c5b0a73a

To get around this, you need to use a type eraser https://medium.com/dunnhumby-data-science-engineering/swift-associated-type-design-patterns-6c56c5b0a73a

这篇关于使用泛型将符合协议的对象和泛型存储在类型数组中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆