Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics kotlin中的out关键字是什么_Generics_Kotlin - Fatal编程技术网

Generics kotlin中的out关键字是什么

Generics kotlin中的out关键字是什么,generics,kotlin,Generics,Kotlin,我无法理解,也无法在kotlin中找到out关键字的含义 您可以在此处查看示例: List<out T> 列表 如果有人能解释这句话的意思。非常感谢。请参阅 Kotlin列表类型是一个提供只读的接口 像size、get等操作。与Java一样,它继承自 集合,而该集合又继承自Iterable。方法 通过MutableList界面添加更改列表。这 模式也适用于Set/MutableSet和Map/MutableMap 而这个, 在科特林,有一种方法可以向公众解释这类事情 编译器。这称

我无法理解,也无法在kotlin中找到out关键字的含义

您可以在此处查看示例:

List<out T>
列表
如果有人能解释这句话的意思。非常感谢。

请参阅

Kotlin
列表
类型是一个提供只读的接口 像size、get等操作。与Java一样,它继承自
集合
,而该集合又继承自
Iterable
。方法 通过
MutableList
界面添加更改列表。这 模式也适用于
Set/MutableSet
Map/MutableMap

而这个,

在科特林,有一种方法可以向公众解释这类事情 编译器。这称为声明站点差异:我们可以注释 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
>     // ... }
>抽象类源代码{
>抽象趣味nextT():T}
> 
>趣味演示(strs:来源){
>val objects:Source=strs//这是可以的,因为T是一个out参数
>     // ... }
一般规则是:当声明类
C
的类型参数
T
时 out,它可能只出现在
C
的成员中的out位置,但在 return
C
可以安全地成为
C
的超类型

在“聪明的话”中,他们说类
C
在 参数
T
,或者
T
是协变类型参数。你可以想到 C作为T的生产者,而不是T的消费者。 out修饰符称为方差注释,因为它是 在类型参数声明站点提供,我们讨论 申报地点差异。这与Java的使用站点形成对比 方差,其中类型用法中的通配符使类型协变

签名如下:

List<out T>
因此,当需要
列表
时,可以安全地提供
列表
,因此
列表
列表
的超级类型,但反之亦然

List<out T> is like List<? extends T> in Java
可比
的示例中:

因此,当需要
compariable
时,可以安全地提供
compariable
,因此
compariable
compariable
的超级类型,但反之亦然。

列表类似于列表请记住:

List<out T> is like List<? extends T> in Java
in
是“forinput”-你想把(写)东西放进去(所以它是“消费者”)

out
是“foroutput”-你想从中获取(阅读)一些东西(因此它是“制作人”)

如果你来自爪哇


是用于输入的,所以它就像
方差修饰符
out
in
允许我们通过允许子类型来减少泛型类型的限制性和可重用性

让我们通过对比的例子来理解这一点。我们将使用案例作为各种武器的容器。假设我们有以下类型层次结构:

open class Weapon
open class Rifle : Weapon()
class SniperRifle : Rifle()

out
生成
T
并保留子类型 当您使用
out
修饰符声明泛型类型时,它被称为协变。协变变量是
T
的生产者,这意味着函数可以返回
T
,但不能将
T
作为参数:

class Case<out T> {
    private val contents = mutableListOf<T>()
    fun produce(): T = contents.last()         // Producer: OK
    fun consume(item: T) = contents.add(item)  // Consumer: Error
}
使用
out
修饰符,子类型被保留,因此
Case
Case
的子类型,而
sniperifle
Rifle
的子类型。因此,
useProducer()
函数也可以通过
Case
调用:

useProducer(Case<SniperRifle>())               // OK
useProducer(Case<Rifle>)                       // OK
useProducer(Case<Weapon>())                    // Error
useConsumer(Case<SniperRifle>())               // Error          
useConsumer(Case<Rifle>())                     // OK
useConsumer(Case<Weapon>())                    // OK
中的
修饰符声明的
案例
使用
T及其子类型:

fun useProducer(case: Case<Rifle>) {
    // Produces Rifle and its subtypes
    val rifle = case.produce()
}
fun useConsumer(case: Case<Rifle>) {
    // Consumes Rifle and its subtypes
    case.consume(SniperRifle())
}
fun useProducerConsumer(case: Case<Rifle>) {
    // Produces Rifle and its subtypes
    case.produce()
    // Consumes Rifle and its subtypes
    case.consume(SniperRifle())
}
这在消费时限制较少,并且更易于重用,但我们的类变成了只写类


不变量产生并使用
T
,不允许子类型 当您在没有任何方差修饰符的情况下声明泛型类型时,它被称为不变量。不变量是
T
的生产者和消费者,这意味着函数可以将
T
作为参数,也可以返回
T

class Case<in T> {
    private val contents = mutableListOf<T>()
    fun produce(): T = contents.last()         // Producer: Error
    fun consume(item: T) = contents.add(item)  // Consumer: OK
}
class Case<T> {
    private val contents = mutableListOf<T>()
    fun produce(): T = contents.last()         // Producer: OK
    fun consume(item: T) = contents.add(item)  // Consumer: OK
}
如果没有
in
out
修饰符,则不允许使用子类型,因此现在
Case
Case
都不是
Case
的子类型。因此,
useProducerConsumer()
函数只能在使用
Case
的情况下调用:

useProducerConsumer(Case())//错误
useProducerConsumer(Case())//确定
useProducerConsumer(Case())//错误
这在生产和消费时限制性更强,可重用性更低,但我们可以读写


结论 Kotlin中的
列表
仅为生产者。因为它是使用
out
修饰符声明的:
List
。这意味着您不能向它添加元素,因为
add(element:T)
是一个消费函数。每当您希望能够
get()
以及
add()
元素时,请使用不变版本
MutableList


就这样!希望这有助于理解方差的
in
s和
out
s

这些答案解释了
输出
的功能,但不解释为什么你需要它,所以让我们假装我们根本没有输出。想象三个类:Animal、Cat、Dog和一个包含
Animal

abstract class Animal {
  abstract fun speak()
}

class Dog: Animal() {
  fun fetch() {}
  override fun speak() { println("woof") }
}

class Cat: Animal() {
  fun scratch() {}
  override fun speak() { println("meow") }
}
由于
动物
的一个子类型,我们希望使用
列表
作为
列表
的一个子类型,这意味着我们希望能够做到:

fun allSpeak(animals: List<Animal>) {
    animals.forEach { it.speak() }
}

fun main() {
  val dogs: List<Dog> = listOf(Dog(), Dog())
  allSpeak(dogs)

  val mixed: List<Animal> = listOf(Dog(), Cat())
  allSpeak(mixed)
}

你不能安全地认为<代码> MutableList <代码>是一个子类型:<代码> MutableList <代码>,因为你可以对后者做些事情(插入一个猫),这是你不能做的。

fun useConsumer(case: Case<Rifle>) {
    // Consumes Rifle and its subtypes
    case.consume(SniperRifle())
}
useConsumer(Case<SniperRifle>())               // Error          
useConsumer(Case<Rifle>())                     // OK
useConsumer(Case<Weapon>())                    // OK
class Case<T> {
    private val contents = mutableListOf<T>()
    fun produce(): T = contents.last()         // Producer: OK
    fun consume(item: T) = contents.add(item)  // Consumer: OK
}
fun useProducerConsumer(case: Case<Rifle>) {
    // Produces Rifle and its subtypes
    case.produce()
    // Consumes Rifle and its subtypes
    case.consume(SniperRifle())
}
useProducerConsumer(Case<SniperRifle>())       // Error
useProducerConsumer(Case<Rifle>())             // OK
useProducerConsumer(Case<Weapon>())            // Error
abstract class Animal {
  abstract fun speak()
}

class Dog: Animal() {
  fun fetch() {}
  override fun speak() { println("woof") }
}

class Cat: Animal() {
  fun scratch() {}
  override fun speak() { println("meow") }
}
fun allSpeak(animals: List<Animal>) {
    animals.forEach { it.speak() }
}

fun main() {
  val dogs: List<Dog> = listOf(Dog(), Dog())
  allSpeak(dogs)

  val mixed: List<Animal> = listOf(Dog(), Cat())
  allSpeak(mixed)
}
fun processAnimals(animals: MutableList<Animal>) {
   animals.add(Cat()) // uh oh, what if this is a list of Dogs?
}

fun main() {
  val dogs: MutableList<Dog> = mutableListOf(Dog(), Dog())
  processAnimals(dogs) // we just added a Cat to a list of Dogs!
  val d: Dog = dogs.last() // list of Dogs, so return type of .last() is Dog
                           // but this is actually a Cat
  d.fetch() // a Cat can't fetch, so what should happen here?
}
val dogs: MutableList<Dog> = mutableListOf(Dog())
val anything: MutableList<Any> = dogs
// now I can add any type I want to the dogs list through the anything list
anything.add("hello world")