Swift泛型数组

7

如何创建一个泛型数组?例如:

struct Thing<Any> {
}

let intThing = Thing<Int>()
let stringThing = Thing<String>()

// This line doesn't compile
// Cannot convert value of type 'Thing<Int>' to expected type 'Thing'
let things: [Thing] = [intThing, stringThing]

我该如何声明一个任意类型的泛型(类似于 Thing<?>Thing<Any>)?

很遗憾,泛型目前不能与这种模式一起使用。 - GetSwifty
4个回答

5
你可以这样做:
let things: [Any] = [intThing, stringThing] Thing本身不是一个有效的类型。 Thing<String>是一种类型,而Thing<Int>是另一种类型,你不能在数组中混合不同类型。
你是否注意到即使let things:[Thing]也不能编译?
我认为你可能正在尝试的最好方法是使用带关联值的枚举。
struct MyStruct<T> {

    let property: T
    init(property: T) {
        self.property = property
    }
}

enum Thing {
    case int(Int)
    case string(String)
    case intStruct(MyStruct<Int>)
}

// creation
let myInt = Thing.int(2)
let myString = Thing.string("string")
let myIntStruct = Thing.intStruct(MyStruct<Int>(property: 3))

// down side is that you need a 'case' clause to retrieve the data
switch myIntStruct {
case let .int(value):
    print("have a int: \(value)")
case let .string(value):
    print("have a string: \(value)")
case let.intStruct(value):
    print("have a intStruct\(value)")
}

// An array of Thing
let things: [Thing] = [myInt, myString, myIntStruct]

这里有一篇关于高级枚举技巧的好文章
在这个文件中,介绍了将Plist数据封装到单个结构中的方法,并使用了一个枚举来表示实体类型。


您可以将任何内容与枚举值关联,但它必须是完全限定的类型。因此,您不能使用MyStruct,因为它不是完全限定的,您需要使用MyStruct<Int>来完全限定。这意味着您需要为要与MyStruct一起使用的每个通用类型创建一个案例。
这就是您的通用方法所能达到的范围。
我不确定您想要做什么。但是,如果您想实现某种依赖于操作T的方法但不使用T作为输入或输出的多态性,您应该使您的Thing实现协议,并创建该协议的数组,并在该协议上调用您的多态方法。

谢谢,这样的枚举看起来是什么样子? - Steve Kuo
我的 Thing 结构实际上有一些属性,据我所知,这是枚举无法实现的。 - Steve Kuo
@SteveKuo,我已更新代码,以便您可以看到它如何与通用类型一起工作,但是您需要为每种 T 准备一个案例。 - Vincent Bernier
@VincentBernier,如果我有类型约束的东西,你会如何使其工作?比如说,我已经限制了我的泛型,使它们必须符合某个协议,现在我不能使用 Any,因为它不符合该协议。 - A Tyshka

3

您可以使用枚举

enum Thing {
    case Text(String)
    case Integer(Int)
}

现在,您可以创建一个包含字符串或整数的物体。
let thingWithText = Thing.Text("Hello world")
let thingWithInt = Thing.Integer(123)

你可以将它们放在一个Thing(s)数组中(无需泛型参与)。

let things = [thingWithText, thingWithInt]

最后,您可以按照以下方式处理数组中的值。
things.forEach { (thing) -> () in
    switch thing {
    case .Text(let text): print(text)
    case .Integer(let integer): print(integer)
    }
}

0

这将会有所帮助

protocol Six {}
struct Thing<Any> :Six {}

let intThing = Thing<Int>()
let stringThing = Thing<String>()
let things: [Six] = [intThing, stringThing]

0
您可以使用包含您想要使用的所有相关属性和函数的协议:
protocol ThingProtocol {
    func doSomething()

    // if you want to expose generic functions/properties
    // use functions/properties which have the most specific type
    // for Thing<T: AProtocol> it should be `var anyValue: AProtocol { get }`
    // here: `Any` since T in Thing<T> can be anything
    var anyValue: Any { get }
}

struct Thing<T>: ThingProtocol {
    var value: T

    // ThingProtocol implementation
    var anyValue: Any { return value as Any }
    func doSomething() { ... }
}

let intThing = Thing<Int>(value: 42)
let stringThing = Thing<String>(value: "101010")

let things: [ThingProtocol] = [intThing, stringThing]

things[0].doSomething()
things[0].anyValue // returns a value of type Any

// you cannot call `value` since it is not specified in the protocol. If you do it, it would result in an error in `Thing<T>`
things[0].value // error

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接