无法分配泛型类型的值

Posted

技术标签:

【中文标题】无法分配泛型类型的值【英文标题】:Cannot assign value of generic type 【发布时间】:2016-12-26 08:03:59 【问题描述】:

我有通用类 - Class1

class Class1<T> 

我有 Class2 变量 object1 类型为 Class1 和泛型类型 UIView

class Class2 
    var object1: Class1<UIView>?

当我创建Class2 的实例并尝试分配给object1 类型Class1 和泛型类型UITableView 的实例时,我收到一个错误:“无法将Class1&lt;UITableView&gt; 类型的值分配给Class1&lt;UIView&gt; 类型"

var c = Class2()
c.object1 = Class1<UITableView>()

不过,同样的逻辑也适用于 Array。为什么?

【问题讨论】:

我认为Array 类型发生了一些编译器魔法。从技术上讲,Generic&lt;Supertype&gt;Generic&lt;Subtype&gt; 的类型不同,您不能将后者的值分配给前者的属性。但在数组的情况下,你可以看到它确实有效。 This answer 可能对您要查找的内容有用... 【参考方案1】:

让我详细说明安东的评论。问题是何时可以将 B 用于 A。通常,当 B 是 A 的子类型时,您可以这样做。例如,您可以将 UITableView 分配给 UIView 类型的变量。

那么什么时候是其他东西的子类型?

对于类,这很简单:如果您从A 继承B,则BA 的子类型。

对于函数类型,您需要考虑参数类型和返回类型。如果F2 的参数类型是F1 的参数的超类型并且F2 的返回类型是F1 的返回的子类型,则函数类型F2 是函数类型F1 的子类型类型。你可以说一个函数不能要求更多(即它不能要求子类型作为参数但可以要求超类型)并且不能提供更少(即它不能返回超类型但可以返回子类型)以使其类型成为子类型.术语是参数类型必须是逆变,返回类型必须是协变

例子:

var f1: UIControl -> UIControl = ...

let f2: UIView -> UIControl = ...
let f3: UIControl -> UIButton = ...
let f4: UIView -> UIButton = ...
f1 = f2  // Fine, f2 takes UIView so it also takes UIControl
f1 = f3  // Fine, f3 returns UIButton which is a UIControl
f1 = f4  // Fine, both of the above

let f5: UIButton -> UIControl
let f6: UIControl -> UIView
let f7: UIButton -> UIView
f1 = f5  // Error, couldn’t call with a UIControl because f5 demands at least a UIButton
f1 = f6  // Error, call would return only a UIView
f1 = f7  // Error, both of the above

所以f2f3f4的类型是f1类型的子类型,f5f6f7的类型不是。

现在泛型类型呢?在 Swift 中,带有类型参数的自定义类型都是不变的。也就是说,在您的示例中,无论T1T2 之间的关系如何,都不能将Class1&lt;T2&gt; 对象用作Class1&lt;T1&gt; 对象(除非T1T2 是同一类型)。

然而,Swift 确实有一些内置的方差规则可以让你的数组示例工作:[UITableView] (Array&lt;UITableView&gt;) 是 [UIView] (Array&lt;UIView&gt;) 的子类型。请注意,选项也是如此,即UITableView? (Optional&lt;UITableView&gt;) 是UIView? (Optional&lt;UIView&gt;) 的子类型。所以数组和可选项都与它们的类型参数是协变的。

进一步阅读:

Liskov Substitution Principle on Wikipedia Mike Ash on Covariance and Contravariance

【讨论】:

以上是关于无法分配泛型类型的值的主要内容,如果未能解决你的问题,请参考以下文章

泛型类派生子类

无法将X类型转换为T.泛型类中的泛型委托

当类的泛型相关时,如何在两个泛型类之间创建类似子类型的关系呢

C#关于反射创建泛型类

自定义泛型结构:泛型类泛型接口泛型方法

Java泛型