简体   繁体   English

混合泛型类型的 Swift 数组

[英]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'错误:无法将类型“Test”的值转换为预期的元素类型“Test”

Update: following Brduca's answer更新:按照 Brduca 的回答

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.基本上,您为 Test 创建基类,并在从数组访问时将要调用的任何函数放在上面。 Also you can make it implement Equatable or create another reusable class that implements it:你也可以让它实现 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() // :)  

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.这对我来说就像个笑话……多年来一直在编写简单的泛型列表,但由于大量愚蠢的类型安全限制使开发更加耗时,所以 swift 不允许这样做。

Sure this is solution just for certain situations...当然,这只是针对某些情况的解决方案......

You got this error, because heterogeneous collection literal could only be inferred to '[Any]' .您收到此错误,因为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.这意味着编译器无法解析关系 btw Test<String, Double>Test<String, Array><String, Any>类型。

It is same as you would tried to put Int and String into array without specifying it as [Any] .这与您尝试将IntString放入数组而不将其指定为[Any]相同。

As a solution you can use Brduca's answer or you can mark your array as [Any]作为解决方案,您可以使用Brduca 的答案,也可以将数组标记为[Any]

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM