【问题标题】:Scala: buggy type inference?Scala:错误的类型推断?
【发布时间】:2017-04-21 01:55:33
【问题描述】:

以下是我原始代码的简化版本,让事情变得更简单(抱歉还是有点复杂):

trait BuilderBase
trait MessageBase {
  type Builder <: BuilderBase
}
class SomeMessage extends MessageBase {
  type Builder = SomeMessage.Builder
}
object SomeMessage {
  class Builder extends BuilderBase
}
class Covariant[+T]
class NonCovariant[T]
def func[T <: MessageBase](value: Covariant[T]): Covariant[T#Builder] = null

val message: Covariant[SomeMessage] = null
val result: Covariant[SomeMessage.Builder] = func(message)

最后一行编译失败,在func(→ message ← here)报错:

类型不匹配;发现:需要协变[SomeMessage]:协变[SomeMessage.type]

func 肯定接受 T 的 Covariant 参数,它是 MessageBase 的子类,这里需要的是 Covariant[SomeMessage] 而不是 Covariant[SomeMessage.type],因为 SomeMessage.type(伴生对象 SomeMessage 的类型)不符合 MessageBase .

奇怪的是,没有类型注释,错误就消失了,比如val result = func(message),结果的类型与它的含义完全相同:协变[SomeMessage.Builder]。所以它只是失败了正确的类型注释。这是一个错误吗?

另一个线索是,所有 Covariant 都替换为 NonConvariant 时不会发生这种情况。所以它可能与协方差有关。任何建议或帮助将不胜感激。


我知道一些小调整可以解决这个特定问题,例如简单地省略类型注释可能就是其中之一。但是,如果我能获得更多关于编译器实际情况的线索,例如通过提供一些命令行选项,那将非常有帮助。

【问题讨论】:

    标签: scala type-inference


    【解决方案1】:

    我也不知道原因,但是为了稍微替代@AssafMendelson 的答案,以下方法也可以:

    trait BuilderBase
    
    trait MessageBase {
      type Builder <: BuilderBase
    }
    class SomeMessage extends MessageBase {
      type Builder = BuilderBase {}
    }
    
    class Covariant[+T]
    class NonCovariant[T]
    def func[T <: MessageBase](value: Covariant[T]): Covariant[T#Builder] = null
    
    val message: Covariant[SomeMessage] = null
    val result: Covariant[SomeMessage#Builder] = func(message)
    

    所以基本上不用在伴生对象中定义类,只要在类中定义就可以了

    【讨论】:

    • 这也可以是一个临时解决方案。但是我真的不想改变这里的结构设计,除非我在这里所做的事情是错误的或不允许的。如果这真的是一个错误,我将不得不向 scala 团队报告。
    【解决方案2】:

    我认为问题在于编译器被类型参数 Builder 和类 Builder 弄糊涂了

    基本上 SomeMessage.Builder 可以引用继承的类型和对象,但是,它首先尝试实例,然后才尝试对象。

    我尝试了一个简单的更改:我将类构建器更改为 builder2(以及对它的相关引用),它似乎可以工作。

    【讨论】:

    • 嗯..看错误信息,相信编译器把SomeMessage和SomeMessage.type混淆了,很奇怪,不是SomeMessage.Builder和SomeMessage#Builder,反正这里都是一样的。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-30
    • 1970-01-01
    • 2023-03-08
    • 2012-11-29
    • 2014-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多