代码之家  ›  专栏  ›  技术社区  ›  Thomas Joulin

混合泛型类型的Swift数组

  •  2
  • Thomas Joulin  · 技术社区  · 7 年前

    想知道为什么这不可能:

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

    我收到一个错误:

    错误:无法将“Test”类型的值转换为预期值 元件类型“测试”

    更新:遵循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 回复  |  直到 7 年前
        1
  •  2
  •   brduca    7 年前

    无需显式键入:

    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)
    ]
    
        2
  •  0
  •   Renetik    5 年前

    我找到了“变通方法”,但没人喜欢。基本上,您可以为测试创建基类,并在从数组访问时将希望调用的任何函数放在基类上。您还可以使其实现Equalable,或创建另一个实现它的可重用类:

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

    这对我来说就像一个笑话。。。编写简单的泛型列表已经有好几年了,但swift就是不允许,因为它有无数愚蠢的类型安全限制,使开发更加耗时。

    当然,这只是针对某些情况的解决方案。。。

        3
  •  -1
  •   Ahmad F    7 年前

    你犯了这个错误,因为 heterogeneous collection literal could only be inferred to '[Any]'

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

    这和你想说的一样 Int String 插入数组,而不将其指定为 [Any]

    作为您可以使用的解决方案 Brduca's answer 或者可以将数组标记为 [任何]

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