【问题标题】:Kotlin generics inheritance headacheKotlin 泛型继承头痛
【发布时间】:2016-11-01 18:37:42
【问题描述】:

我是 Kotlin 的新手,我正在尝试编译这段代码但没有成功(这只是我想在实际项目中做的一个例子):

abstract class Builder<T: Any, Y: Any> 

class BuilderImpl() : Builder<String, Int>()

abstract class Shape<T: Any>(){
     abstract var builder: Builder<T, *>
}

class Circle() : Shape<String>(){
     override var builder: Builder<String, Int> = BuilderImpl()
}

我想覆盖 Circle 类中 Shape 类的 builder 属性。 Shape 类只知道 Builder 类的第一个泛型类型。第二个可以是任何类型,所以我使用 *。

当我尝试覆盖 Circle 类中的 builder 属性时,编译器会报错:

  "Var-property type is 'Builder<String, Int>', which is not a type of overriden public abstract var builder: Builder<String, *>".

我也尝试过用“out Any”代替*,但没有成功。

我不知道如何编译这段代码。

【问题讨论】:

    标签: android generics kotlin


    【解决方案1】:

    当您覆盖 var 属性时,编译器会强制执行该操作

    • 获取被覆盖属性的值是类型安全的:如果原始属性的类型为S,则被覆盖的属性应返回S的实例,即其类型应为S或它的子类型(例如,当需要 Number 时返回 Int 是安全的);

    • 设置被覆盖属性的值是类型安全的:如果原始属性的类型为S,被覆盖的属性应该接受S的对象作为它的值,所以它的类型应该是S或它的一些超类型(例如,如果我们需要存储String,则将其存储为Any 即可)

    鉴于这两个要求,被覆盖的var 属性可以具有的唯一类型是原始属性类型本身,因为它的子类型和超类型将违反上述条件之一。例如,被覆盖的属性应该仍然能够存储Builder&lt;T, *&gt;,并且不能将其类型指定为Builder&lt;T, Int&gt;

    val s: Shape<SomeType> = Circle<SomeType>()
    val b: Builder<SomeType, *> = someBuilder
    
    s.builder = b // should be type-safe, but won't be with the override you want to do
    

    因此,当您覆盖 var 属性时,您根本无法更改它的类型,因为就 Kotlin 泛型而言,它位于 inout 位置。

    但是,您可以尝试以下选项之一:

    • 更改为 val 属性。在这种情况下,没有第二个要求,您可以将属性的类型更改为原始属性类型的子类型:

      abstract class Shape<T: Any>(){
          abstract val builder: Builder<T, *>
      }
      
      class Circle() : Shape<String>(){
          override var builder: Builder<String, Int> = BuilderImpl() // OK
      }
      
    • 添加一个泛型参数并在子类中指定它。在这种情况下,您将能够使用var,因为Circle 将是特化Shape&lt;String, Int&gt; 的子类型,而不是原始类型Shape&lt;T, R&gt;

      abstract class Shape<T: Any, R: Any>(){
          abstract var builder: Builder<T, R>
      }
      
      class Circle() : Shape<String, Int>(){
          override var builder: Builder<String, Int> = BuilderImpl() // OK
      }
      

    【讨论】:

    • 用您可以尝试的另一个选项更新了答案。
    • 非常感谢!第一个选项就可以了!
    猜你喜欢
    • 2017-10-28
    • 1970-01-01
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-25
    相关资源
    最近更新 更多