什么是Kotlin关键字


85

我听不懂,在kotlin中找不到out关键字的含义。

您可以在此处查看示例:

List<out T>

如果有人可以解释这个意思。我们将不胜感激。

Answers:


58

带有此签名:

List<out T>

你可以这样做:

val doubleList: List<Double> = listOf(1.0, 2.0)
val numberList: List<Number> = doubleList

这意味着T协变的

当声明C的类型参数TC <Base>可以安全地为C <Derived>超类型

in形成对比,例如

Comparable<in T>

你可以这样做:

fun foo(numberComparable: Comparable<Number>) {
  val doubleComparable: Comparable<Double> = numberComparable
  // ...
}

这意味着T协变的

当类型参数Ť一类Ç被声明ç<派生>可以安全地是一个超型ç<数据库>

记住它的另一种方式:

消费者进入,生产者退出

参见Kotlin泛型方差

-----------------于2019年1月4日更新-----------------

对于“ Consumer in,Producer out ”,我们仅从Producer-call方法读取以获取类型T的结果。并且只能通过传入T类型的参数来写入Consumer-call方法。

在的示例中List<out T>,很明显,我们可以执行以下操作:

val n1: Number = numberList[0]
val n2: Number = doubleList[0]

因此它是安全的提供List<Double>List<Number>的预期,因而List<Number>是超类型的List<Double>,而不是相反。

在以下示例中Comparable<in T>

val double: Double = 1.0
doubleComparable.compareTo(double)
numberComparable.compareTo(double)

因此它是安全的提供Comparable<Number>Comparable<Double>的预期,因而Comparable<Double>是超类型的Comparable<Number>,而不是相反。


1
我认为对于一个List<out T>可见的声明来说,最重要的一点 是out使它不可变(与可变集合相比,后者没有)。在回答中可能需要提及并强调这一点。隐式强制转换是此结果而不是要点的结果(因为不能写List <Number>,因此可以安全地将其作为List <Double>的引用)。
明斯克,

39
抱歉,但仍然无法理解。
Akshay Taru '18

2
@minsk该out部分并不是使List不可变的部分。您可以轻松地创建List<out T>具有clear()方法的自己的接口,因为它不需要任何参数。
Nick Lowery

在您真正需要在代码中的某个位置之前,这可能是您可能想要获得的主题之一。
lasec0203

109
List<out T> is like List<? extends T> in Java

List<in T> is like List<? super T> in Java

例如,在Kotlin中,您可以执行以下操作

 val value : List<Any> = listOf(1,2,3)
//since List signature is List<out T> in Kotlin

1
这个答案是倒退的。List<out T>表示您可以执行,val list: List<Number> = listOf<Int>()因为Int是的派生类型Number。等效的Java是List<? extends Number> list = new ArrayList<Integer>();
Nick Lowery

好一点,在Java中,它是“?extended T”,而不是“?super T”。固定。我没有提到我们在不同的地方定义方差以保持答案简单。每个人都可以查阅官方文档以获取所有详细信息。所以我不明白您所说的“答案是倒退”是什么意思。
DmitryBorodin '18

4

请参阅Kotlin的手册

KotlinList<out T>类型是提供只读操作(如大小,获取等)的接口。像Java中一样,它继承自 Collection<T>,而继承自Iterable<T>MutableList<T>界面会添加更改列表的方法。此模式也适用于Set<out T>/MutableSet<T>Map<K, out V>/MutableMap<K, V>

和这个,

在Kotlin中,有一种方法可以向编译器解释这种情况。这称为声明位置方差:我们可以注释Source的类型参数T,以确保仅从(的)成员返回(产生)它Source<T>,而从不使用它。为此,我们提供out修饰符:

> abstract class Source<out T> {
>     abstract fun nextT(): T }
> 
> fun demo(strs: Source<String>) {
>     val objects: Source<Any> = strs // This is OK, since T is an out-parameter
>     // ... }

一般规则是:当声明T一个类的类型参数C时,它只能出现在成员中的外位置C,但C<Base>可以安全地返回的超类型C<Derived>

在“灵巧的词”中,他们说类别C在参数中是协变的T,或者T是协变类型参数。您可以将C视为T的生产者,而不是T的消费者T。out修饰符称为方差注释,由于它是在类型参数声明站点提供的,因此我们讨论声明站点方差。这与Java的使用站点差异相反,在Java中,使用类型中的通配符使类型成为协变。


3

记住这样:

in是“为放” -你想放(写)的东西进去(所以这是一个“消费者”)

out是“换”的-您想从中取出(读取)某些内容(因此它是“制作人”)

如果您来自Java,

<in T>用于输入,所以就像<? super T>(消费者)

<out T>用于输出,所以就像<? extends T>(生产者)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.