字段的安装程序通过types投影来删除

我有以下的SSCCE:

class Foo(val bars: Map<Int, Bar>) { fun  qux(baz: Baz) { val bar2 = bars[2]!! bar2.bazes += baz } interface Bar { var bazes: MutableList } } 

这对我来说似乎很好,但编译器抱怨:

 Error:(5, 9) Kotlin: Setter for 'bazes' is removed by type projection 

我不知道这意味着什么,更不用说如何纠正它。 这里发生了什么,如何解决这个问题?

有一些小问题。 暂时使用bars[2]!! as Bar bars[2]!! as Bar

 w: (4, 20): Unchecked cast: Foo.Bar to Foo.Bar e: (5, 20): Assignment operators ambiguity: public operator fun  Collection.plus(element: Baz): List defined in kotlin.collections @InlineOnly public operator inline fun  MutableCollection.plusAssign(element: Baz): Unit defined in kotlin.collections 

Kotlin不知道是否将其作为bar2.bazes = bar2.bazes.plus(baz)bar2.bazes.plusAssign(baz) 。 如果将其更改为var2.bazes.add(baz)val bazes则歧义消失。

解决这个问题,并消除不安全的演员提出

 e: (5, 20): Out-projected type 'MutableList' prohibits the use of 'public abstract fun add(element: E): Boolean defined in kotlin.collections.MutableList' 

types投影可以安全地做什么的问题。 它得到像对待out Any?处理out Any? ,所以你可以从列表中读取,但in Nothing ,这意味着你不能添加任何东西到列表中。

从这个例子不清楚你为什么使用* 。 如果不引起任何其他问题,也许你可以拿出参数,例如

 class Foo(val bars: Map>) 

问题:你的bars属性是使用“星形投影”,简单地说就是:“我不知道Bar的通用types”。 这反过来导致了一个问题:你只能从MutableList 获得某些东西,禁止添加 (因此错误消息:无法使用Setter )。

可能的解决方案:

  class Foo(private val bars: Map>) { fun qux(baz: Baz) { val bar2 = bars[2]!! bar2.bazes.add(baz) } interface Bar { var bazes: MutableList } } 

我在这里改变的是,我把Foo打成了in Baz ,这意味着Foo在其types参数上是逆变的 ,因此Baz只能被消费。 然后相同的types用于输入参数bars 。 因此,您现在可以添加bars.bazes ,因为关联的MutableList被认为是Bar的“消费者”。

btw:不建议使用Baz作为genericstypes的名称 – 您应该使用更明显的genericstypesT

我知道,这是一个复杂的话题,我真的建议咨询好的文档作为更进一步的步骤:)

plusAssign问题

另一方面+=plusAssign运算符)的用法plusAssign :编译器抱怨不能选择正确的运算符:

作业运算模糊:
在kotlin.collections中定义了公共运算符fun Collection.plus(element:Any?):List>

@InlineOnly public operator inline fun MutableCollection.plusAssign(element:Baz):在kotlin.collections中定义的单位

我试图明确地投给MutableList ,这实际上解决了这个问题。 编译器然后抱怨一个不必要的演员,虽然。 我不知道如何处理这个正确的,除了使用add而不是诚实的;-)