Swift数组的混合泛型类型

时间:2018-03-14 09:49:06

标签: swift generics

想知道为什么这是不可能的:

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: [])
]

我收到错误:

  

错误:无法转换类型的值&#39;测试&#39;预期   元素类型&#39;测试&#39;

更新:遵循Brduca的回答

为什么会这样:

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

但这并不是:

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

我收到此错误:

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

3 个答案:

答案 0 :(得分:1)

无需明确输入:

class Test<T, U> {

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

}

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

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

更新

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

答案 1 :(得分:0)

您收到此错误,因为heterogeneous collection literal could only be inferred to '[Any]'

这意味着编译器无法解析btw Test<String, Double>Test<String, Array><String, Any>类型的关系。

与将IntString放入数组而未将其指定为[Any]的情况相同。

作为解决方案,您可以使用Brduca's answer,也可以将数组标记为[Any]

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

答案 2 :(得分:0)

我找到了“解决方法”,但没人能喜欢。基本上,您为Test创建基类,并在从数组访问时将要调用的任何函数放在该基类上。您也可以使它实现Equatable或创建另一个实现它的可重用类:

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() // :)  

这对我来说就像是在开玩笑...编写简单的泛型列表已有很长时间,但由于存在愚蠢的类型安全限制,使得开发工作更加耗时。

确定这只是针对某些情况的解决方案...