混合泛型类型的Swift数组

4

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

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”的值转换为预期的元素类型“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)
]

I'm getting this error:

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

1
这是关于泛型的一个常见误解。Test<String, Double> 不是 Test<String, Any> 的子类型。 - Sulthan
3个回答

2

不需要显式地输入:

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

谢谢!这个可以用,但我想我把我的例子简化得太多了。我仍然想做的事情不起作用...如果您能看一下,我更新了我的问题。 - Thomas Joulin
好的,问题在于:您正在尝试将一个类型为(T,U)的匿名函数进行强制转换(这意味着您的代码块函数接收的参数是 T 和 U)。因此,如果您说“字符串和任何”,块是一个接收字符串和任何类型参数的函数。问题不在于尝试将某个类型转换为任何类型,而是将一个类型的函数转换为另一个类型的函数。 - brduca
但是为什么当参数是单个值而不是块时它能够工作呢?无论如何,我会接受你的答案,看起来我想做的事情并不完全可能 :p - Thomas Joulin
字符串可以转换为 AnyObject(很简单),但您要尝试实现的是类似于:func foo(a:String, b:Int) 并将其转换为 func foo(a:String, b:AnyObject)。 - brduca

0

我找到了“解决方法”,但没有人会喜欢它。基本上,您需要为测试创建基类,并在从数组访问时调用所需的任何函数。此外,您可以使其实现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() // :)  

对我来说就像是个笑话...写简单的泛型列表已经很久了,但是 Swift 由于其亿万愚蠢的类型安全限制,使得开发更加耗时。

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


-1

您看到了这个错误,是因为 异构集合字面量只能被推断成 '[Any]'

这意味着编译器无法解析 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: [])
]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接