通过类型投影删除字段的设置器

时间:2017-08-21 04:45:28

标签: generics kotlin erasure

我有以下SSCCE:

class Foo(val bars: Map<Int, Bar<*>>) {

    fun <Baz> qux(baz: Baz) {
        val bar2 = bars[2]!!
        bar2.bazes += baz
    }

    interface Bar<Baz> {
        var bazes: MutableList<Baz>
    }
}

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

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

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

2 个答案:

答案 0 :(得分:1)

有几个小问题。暂时使用bars[2]!! as Bar<Baz>

w: (4, 20): Unchecked cast: Foo.Bar<Any?> to Foo.Bar<Baz>
e: (5, 20): Assignment operators ambiguity: 
public operator fun <T> Collection<Baz>.plus(element: Baz): List<Baz> defined in kotlin.collections
@InlineOnly public operator inline fun <T> MutableCollection<in Baz>.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<out Any?>' prohibits the use of 'public abstract fun add(element: E): Boolean defined in kotlin.collections.MutableList'

关于类型投影可以安全地做什么的问题。它被视为out Any?,因此您可以从列表中读取,但in Nothing,这意味着您无法向列表中添加任何内容。

从这个例子中不清楚为什么你使用*。如果它没有引起任何其他问题,也许你可以取出<Baz>参数,例如

class Foo<Baz>(val bars: Map<Int, Bar<Baz>>)

答案 1 :(得分:1)

问题:您的bars媒体资源正在使用&#34;星级投影&#34;,简而言之,只是意味着:&#34;我不会知道Bar&#34;的通用类型。这又会导致一个问题:您只能 来自MutableList添加是禁止的(因此错误消息: bazes没有 Setter !)。

可能的解决方案:

 class Foo<in Baz>(private val bars: Map<Int, Bar<in Baz>>) {

    fun qux(baz: Baz) {
        val bar2 = bars[2]!!
        bar2.bazes.add(baz)
    }

    interface Bar<Baz> {
        var bazes: MutableList<Baz>
    }
}

我在此处更改的是,我使用Foo键入了in Baz,这意味着Foo在其类型参数中被设为逆变,因此{{ 1}}只能被消费。然后将相同的类型用于输入参数Baz。因此,您现在能够值添加到bars,因为关联的bars.bazes被认为是&#34;消费者&#34; MutableList s。

btw:使用Bar作为通用类型的名称isn&#39; t recommended - 您应该使用Baz,这更明显是通用类型。

我知道,这是一个复杂的话题,我真的建议再去咨询好documentation :)

plusAssign问题

另一方面,T+=运算符)的使用有点奇怪: 编译器抱怨无法选择正确的运算符:

  

分配操作员歧义:
  public operator fun Collection.plus(element:Any?):List&gt;在kotlin.collections中定义

     

@InlineOnly公共运营商内联乐趣   MutableCollection.plusAssign(element:Baz):单位   在kotlin.collections中定义

我尝试明确地将plusAssign投射到bazes,这实际上解决了这个问题。然后,编译器会抱怨不必要的强制转换。除了使用MutableList之外,我不知道如何正确处理这个问题; - )