Kotlin泛型中的输入和输出位置是什么? 我想从我知道的开始,或者至少我认为我知道的,这样我的问题会更清楚。
首先,我知道您可以声明一个超类型的变量,并分配一个子类型的对象,以利用具有继承性和接口的多态性Kotlin泛型中的输入和输出位置是什么? 我想从我知道的开始,或者至少我认为我知道的,这样我的问题会更清楚。,kotlin,generics,Kotlin,Generics,首先,我知道您可以声明一个超类型的变量,并分配一个子类型的对象,以利用具有继承性和接口的多态性 我知道泛型提供了类型安全性,因为类型参数在定义上是不变的,所以在A是B的子类型的情况下,Foo不一定是Foo的子类型,并且根据对象的易变性,可能不会在适当的位置使用。这样,由于动态调度而在运行时可能出现的异常可以在编译时捕获 它们还有助于为不同类型定义通用逻辑:比如在列表中,您有类型a对象的集合,但它不会更改类型B对象的实现 另外,我理解了为什么MutableList不算作MutableList
Foo
不一定是Foo
的子类型,并且根据对象的易变性,可能不会在适当的位置使用。这样,由于动态调度而在运行时可能出现的异常可以在编译时捕获
MutableList
不算作MutableList
的子类型,因为这可能会导致创建类型为MutableList
的变量,该变量包含对MutableList
对象的引用,并将Int
元素添加到字符串列表中,这显然是个问题
in
的类型参数只能用作正在使用的函数参数,而out
的类型参数可以用作正在生成的函数返回类型
现在谈谈我不明白的部分:
- 我不太明白消费者和生产者这两个词在
和输入
方面的实际含义。类型处于消费或生产位置意味着什么?这是否意味着该类型的对象只能读或写?这和物体有什么关系吗输出
- 如果我们不使用
或in
定义对象,或者相反,我们使用out
或in
定义对象,而不是讨论我上面解释的子类型-超类型关系,那么对象的行为会是什么out
我花了几天的时间来研究不同的解释,但我发现缺乏例子是一个大问题,特别是因为我通常是这样学习的
我可以在代码中使用这些概念,但缺乏基础知识或逻辑会让我非常不安,因此,如果您决定花时间写一篇解释,请提供一些例子和反例,说明某个想法为什么或如何工作。对您的第一个要点只做一个更正:列表不是一成不变的;它是只读的。列表可以是一个向上转换的可变实现,而引用它的其他对象可以对其进行变异 Producer表示泛型类型在对象的任何函数或属性中显示为返回类型。例如,您可以从列表中获取T 使用者表示泛型类型显示为任何函数的参数或对象的任何
var
属性的类型。例如,您可以将T放入可变列表中
由于列表产生但不消耗(它没有任何以t作为参数的函数),因此它的类型在声明站点上被标记为仅产生,即协变,即out
,因此它的类型总是可以假定为out
,无论在何处使用,即使没有使用out
关键字
由于列表类型始终是协变的out
,因此任何列表都可以安全地向上转换为列表,其中该类型是原始类型的超类型。列表
可以强制转换为列表
,因为从中得到的任何项(它产生的任何项)都将是字符串,因此也符合超类型CharSequence的条件
相反的逻辑将适用于纯粹是消费者的东西,其类型在中标记为,但很难给出一个简单的示例,在这个示例中,您将实际拥有这样一个有用的对象
可变列表同时产生和使用,因此默认情况下它是不变的,但由于它也是一个列表,可变列表
可以安全地转换为列表
。如果有对列表的引用
,则可以从中获取字符序列。底层对象可能会继续从原始引用中放入新字符串。现在我看到了它,它们似乎被称为不可变而不是不可变,我甚至不知道这两个是分开的。此外,使用out
类型参数定义的列表帮助我理解了生产者和只读概念,但是,缺少in
的示例仍然是一个问题。如果更多的是放置一些Ts并仅使用受尊重的类型写入,那么我们应该能够将a的引用分配给a,因为
中的具有相反的子类型关系(逆变),对吗?我在文档中没有看到“不可变”这个术语,它可以被解释为与不可变的意思完全相同<代码>列表
被称为“只读”。在Venkat Subramaniam的《编程Kotlin》一书中,有一个伟大的章节“泛型:参数类型的变化和约束”,我认为它完美地涵盖了这个主题(以及许多其他主题)。