简体   繁体   中英

Swift array of generics

How do I create an array of generics? Example:

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]

How do I declare a generic of any type (something like Thing<?> or Thing<Any> )?

You can do this:
let things: [Any] = [intThing, stringThing]

Thing is not a valid type on it's own. Thing<String> is a type and Thing<Int> is an other type and you can't mix different type within an array.

Have you notice that even let things: [Thing] doesn't compile?

I think that what you are probably trying to do would be better server with an enum with associated values.


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]

nice article about advance enum trick here
In this file about wrapping Plist data into a single structure, there is the use of an enum for the EntityType.


You can associate anything to an enum value, but it needs to be a fully qualified type. So you can't use MyStruct because it is not fully qualified, you need to use MyStruct<Int> to fully qualify. This means that you would need to create a case for every generic type you want to use with MyStruct.

That is as far as you can go with your generic approach.
I'm not sure what you are trying to do. But if you want to achieve some kind of polymorphism that relies on methods that operate on T but don't use T as input nor output you should make your Thing implement a protocol and make an array of that protocol and call your polymorphic method on that protocol.

You can use an enum

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

Now you can create a Thing containing a String or an Int

let thingWithText = Thing.Text("Hello world")
let thingWithInt = Thing.Integer(123)

And you can put them inside an array of Thing(s) (no generics involved).

let things = [thingWithText, thingWithInt]

Finally you can process the values inside the array this way

things.forEach { (thing) -> () in
    switch thing {
    case .Text(let text): print(text)
    case .Integer(let integer): print(integer)
    }
}

This will be help

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

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

You can use a protocol which contains all the relevant properties and functions which you want to use:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM