Search code examples
arraysswiftcastingdowncast

Adding arrays of different types


Is there more elegant way of adding two arrays of different types in Swift?

My first try was to downcast an array to Any and just add it.

class BasicClass {
    var name : String = ""
    var number : Int = -1

    init(name : String, number : Int){
        self.name = name
        self.number = number
    }
}

let basicClass1 = BasicClass(name: "bc1", number: 1)
let basicClass2 = BasicClass(name: "bc2", number: 2)
let basicClass3 = BasicClass(name: "bc3", number: 3)

let basicClasses : [BasicClass] = [basicClass1, basicClass2, basicClass3]

for bc in basicClasses{
    print(bc.name)
}

let strings : [String] = ["one", "two", "three"]

var anyArray : [Any] = strings as [Any] + basicClasses as [Any]

I'm asking about this last line.


Solution

  • Creating [Any] this way is a mistake in Swift. There are places that [Any] pops up because of bridging to Cocoa, but you should never create them independently. It is incredibly rare that you mean "an array of absolutely anything at all." If you don't mean "absolutely anything at all is fine," you don't mean Any. (For an example of something that means that, consider print, which correctly accepts "absolutely anything at all.")

    If you want "an array of strings or BasicClasses" then there's a type for that. It's an enum:

    enum Element {
        case basicClass(BasicClass)
        case string(String)
    }
    
    let combined = strings.map(Element.string) + basicClasses.map(Element.basicClass)
    

    This wraps your strings and you BasicClasses in the Element type, and then creates an [Element].

    (Note that I've used + here to combine the arrays because it's just so convenient in this case, but it can create significant problems with compilation time, and it's inefficient because it often forces too many copies. You generally should avoid using + for anything but numbers. But in this example it's just so much prettier than the alternative using .extend.)