You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala 2中如何恢复通配符的类型边界约束?

问题描述

以下代码在Scala 3中可以正常编译运行,但在Scala 2中编译失败:

trait Aggregate[T <: Aggregate[T]] {
  type B = T
  def split(percentage: Double): (T, T)
  def add(other: T): T
}

case class Scoria(total: Int) extends Aggregate[Scoria] {
  override def split(percentage: Double): (Scoria, Scoria) = {
    val amount = (total * (percentage / 100)).toInt
    (Scoria(total - amount), Scoria(amount))
  }

  override def add(other: Scoria): Scoria = copy(total = total + other.total)
}


trait Transporter[T <: Aggregate[T]] {
  def load(aggregate: T): Transporter[T]
}

case class Truck[T <: Aggregate[T]](aggregate: T) extends Transporter[T] {
  override def load(aggregate: T): Transporter[T] = Truck(this.aggregate.add(aggregate))
}


case class SiteProps[T <: Aggregate[T]](aggregate: T, transporter: Transporter[T]) {
  type A = T
  type C = T#B
}


trait Site {

  val props: SiteProps[_]

  private def runWith[T <: Aggregate[T]](props: SiteProps[T]): Unit = {
      val (remaining, going) = props.aggregate.split(50D)
      val loadedTransporter = props.transporter.load(going)
      println(loadedTransporter)
  }

  def run(): Unit = {
    runWith(props)
  }
}


val site = new Site {
  override val props: SiteProps[Scoria] = SiteProps(Scoria(3), Truck[Scoria](Scoria(0)))
}

site.run()

Scala 2中的编译报错信息:

runWith(props)
    ^
<pastie>:49: error: inferred type arguments [_$1] do not conform to method runWith's type parameter bounds [T <: Aggregate[T]]

    runWith(props)
            ^
<pastie>:49: error: type mismatch;
 found   : SiteProps[_$1] where type _$1
 required: SiteProps[T]

我尝试了以下强制类型转换写法,但都无效:

runWith(props.asInstanceOf[SiteProps[props.A]])
runWith(props.asInstanceOf[SiteProps[props.A#B]])
runWith(props.asInstanceOf[SiteProps[props.C]])

请问有没有办法让这段代码在Scala 2中编译通过(允许使用强制类型转换)?

解决方案

方案1:使用正确的强制类型转换写法

Scala 2无法直接通过props.A这类路径依赖类型完成转换,需要明确断言通配符类型满足Aggregate的自类型约束,修改run()方法如下:

def run(): Unit = {
  runWith(props.asInstanceOf[SiteProps[T forSome { type T <: Aggregate[T] }]])
}

或者用模式匹配给通配符类型命名后转换:

def run(): Unit = {
  props match {
    case p: SiteProps[t] => runWith(p.asInstanceOf[SiteProps[t <: Aggregate[t]]])
  }
}

方案2:调整Site的类型定义(无强制转换,更安全)

如果不想依赖强制转换,可以给Site添加抽象类型成员,让类型约束在编译期明确:

trait Site {
  type T <: Aggregate[T]
  val props: SiteProps[T]

  private def runWith(props: SiteProps[T]): Unit = {
    val (remaining, going) = props.aggregate.split(50D)
    val loadedTransporter = props.transporter.load(going)
    println(loadedTransporter)
  }

  def run(): Unit = {
    runWith(props)
  }
}

val site = new Site {
  type T = Scoria
  override val props: SiteProps[Scoria] = SiteProps(Scoria(3), Truck[Scoria](Scoria(0)))
}

这种写法完全符合Scala 2的类型系统规则,不需要任何强制转换,是更推荐的实现方式。

内容的提问来源于stack exchange,提问作者steinybot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 16:27:40