简体   繁体   中英

Swift array of mixed generic types

Wondering why this isn't possible:

class Test<T, U> {

    init(key: T, value: U) {
    }

}

let array: [Test<String, Any>] = [
    Test<String, Double>(key: "test", value: 42),
    Test<String, Array>(key: "test", value: [])
]

I'm getting an error:

error: cannot convert value of type 'Test' to expected element type 'Test'

Update: following Brduca's answer

How come this works:

class Test<T, U> {

    let key: T
    let value: U

    init(key: T, value: U) {
        self.key = key
        self.value = value
    }

}

let properties: [Test<String, Any>] = [
    Test(key: "fontSize", value: []),
    Test(key: "textColor", value: 42)
]

But this doesn't:

class TestBlock<T, U> {

    let key: String
    let block: (T, U) -> Void

    init(key: String, block: @escaping (T, U) -> Void) {
        self.key = key
        self.block = block
    }

}

let block1: (UILabel, CGFloat) -> Void = {
    $0.font = $0.font.withSize($1)
}

let block2: (UILabel, UIColor) -> Void = {
    $0.textColor = $1
}

let propertiesWithBlock: [TestBlock<UILabel, Any>] = [
    TestBlock(key: "fontSize", block: block1),
    TestBlock(key: "textColor", block: block2)
]

I'm getting this error:

Cannot convert value of type 'TestBlock<UILabel, CGFloat>' to expected element type 'TestBlock<UILabel, Any>'

No need to explicitly type:

class Test<T, U> {

    init(key: T, value: U) {
    }

}

let array: [Test<String, Any>] = [

    Test(key: "test", value: []),
    Test(key: "test", value: 42)
]

Update:

typealias tuple = (Any,Any)

class TestBlock
{
    let key: String
    let block: (tuple) -> Void

    init(key: String, block: @escaping (tuple) -> Void)
    {
        self.key = key
        self.block = block
    }
}

let block1: (tuple) -> Void = { (arg) in

    let (_label, _size) = arg
    let label = _label as! UILabel
    label.font = label.font.withSize((_size as! CGFloat))
}

let block2: (tuple) -> Void = { (arg) in

    let (_label, _color) = arg
    let label = _label as! UILabel
    let color = _color as! UIColor
    label.textColor = color
}

let propertiesWithBlock: [TestBlock] = [

    TestBlock(key: "fontSize", block: block1),
    TestBlock(key: "textColor", block: block2)
]

I found "workaround" but nobody can like it. Basically you create base class for Test and put whatever function you want to be called on it when accessed from array. Also you can make it implement Equatable or create another reusable class that implements it:

class TestBase: CSObject {
   open func someFunction(){ fatalError() }
}

open class CSObject: Equatable {
    public static func ==(lhs: CSObject, rhs: CSObject) -> Bool {
        lhs === rhs
    }
}

//Now make your Test extend TestBase and use that in your Arrays:

class Test<T, U> : TestBase {

    init(key: T, value: U) {
    }

    @override func someFunction(){
       //...do some work that is accessible from array
    }
}

let array: [TestBase] = [
    Test<String, Double>(key: "test", value: 42.0),
    Test<String, Array>(key: "test", value: [])
]

array[0].someFunction() // :)  

Its like joke for me... writing simple generics list for ages but swift just doesn't allow due to is milliard of stupid type-safety restrictions that make development more time consuming.

Sure this is solution just for certain situations...

You got this error, because heterogeneous collection literal could only be inferred to '[Any]' .

That means that compiler is not able to resolve relations btw Test<String, Double> , Test<String, Array> and <String, Any> types.

It is same as you would tried to put Int and String into array without specifying it as [Any] .

As a solution you can use Brduca's answer or you can mark your array as [Any]

let array: [Any] = [
    Test<String, Double>(key: "test", value: 42.0),
    Test<String, Array>(key: "test", value: [])
]

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