想知道为什么这是不可能的:
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>'
答案 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>
类型的关系。
与将Int
和String
放入数组而未将其指定为[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() // :)
这对我来说就像是在开玩笑...编写简单的泛型列表已有很长时间,但由于存在愚蠢的类型安全限制,使得开发工作更加耗时。
确定这只是针对某些情况的解决方案...