7

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>)?

1
  • Unfortunately generics don't yet work with this kind of pattern. Commented Mar 5, 2016 at 19:03

4 Answers 4

5

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, what would such an enum look like?
My Thing struct actually has a few properties to it, which as far as I know, isn't doable with enums.
@SteveKuo, I've update the code so that you can see how it could work with generic, but you will need a case for every kind of T.
@VincentBernier, How would you do make this work for something with type constraints? Say I have restricted my generics such that they must conform to a protocol, now I cannot use Any since it doesn't conform to that protocol
3

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)
    }
}

Comments

1

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

Comments

0

This will be help

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

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.