声明一个专用于不同类型的泛型结构的数组

时间:2018-01-09 13:03:38

标签: swift generics

我知道Swift没有通配符类型来专门化泛型类型。我有一个问题,我知道如何使用 Java 等语言来解决这些问题。

在下面的示例中,我尝试定义一个struct Property,它封装了对类型T的属性的访问,以执行两个操作,获取该属性的值的哈希值T的一个实例,并在T的两个实例上比较属性的值。为了实现这一点,struct包含一个属性getter,它包含一个返回实例上特定属性值的函数。因此,结构不仅需要在T中是通用的,还需要属性的类型E

在struct Test中,我想定义一个静态属性properties,其中包含Property个实例的数组,每个属性为Test一个。我无法看到这样做的方法,因为我不知道properties使用什么类型或如何“隐藏”类型参数E,因此不需要在声明中指定它properties

// Struct which represents a property of type T with a value of type E.
// Aside from initialization only T is visible from outside.
public struct Property<T, E: Hashable> {
    let getter: (T) -> E

    func getMemberHashValue(instance: T) -> Int {
        return getter(instance).hashValue
    }

    func equalsMembers(instance1: T, instance2: T) -> Bool {
        return getter(instance1) == getter(instance2)
    }
}

struct Test {
    // Some properties with different types
    let a: Int
    let b: Double

    // Array of Property instances for all properties of Test.
    // Not valid syntax.
    let properties: [Property<Test, ?>] = [
        Property(getter: { (instance: Test) in instance.a }),
        Property(getter: { (instance: Test) in instance.b })]
}

我知道在这种情况下,我可以在properties的声明中替换AnyHashable作为第二个类型参数,因为它没有关联的类型,但我想找到一个我可以应用的通用解决方案不涉及Hashable的案件。

是否有办法更改此示例以允许为不同类型的属性定义包含多个properties实例的属性Property

1 个答案:

答案 0 :(得分:0)

概述:

  • 我不确定我是否理解你的问题。
  • 可能值得说明为什么你想要一个异构数组,在这个过程中会失去所有类型的安全性。
  • 可能会重新审视设计

选项1:

如果绝对需要,如果是,请使用NSArray / NSMutableArray

选项2:

如果您想动态访问class / struct / enum的属性,可以使用KeyPath进行操作。

代码:

struct Test : Hashable {

    // Some properties with different types
    let a: Int
    let b: Double
    let c: String

    //This function will return any property of Test instance
    func property<T>(forKeyPath keyPath: KeyPath<Test, T>) -> T {

        return self[keyPath: keyPath]
    }

    //MARK: Hashable
    var hashValue: Int {
        return a.hashValue ^ b.hashValue ^ c.hashValue
    }

    //MARK: Equatable
    static func ==(lhs: Test, rhs: Test) -> Bool {

        return lhs.a == rhs.a &&
            lhs.b == rhs.b &&
            lhs.c == rhs.c
    }
}

let test1 = Test(a: 10, b: 22.22, c: "aaaa")

let cValue      = test1.property(forKeyPath: \.c)           //aaaa
let cHashValue  = test1.property(forKeyPath: \.c.hashValue) //Hash value of aaaa

let someInt = 10 //This is also Hashable

var mixedArray = [AnyHashable]()

mixedArray.append(test1)
mixedArray.append(someInt)

参见:

如果符合您的要求,请阅读KeyPathPartialKeyPath

版本:

Swift 4