【问题标题】:Is it possible for the Scala compiler to understand overridden Abstract TypesScala 编译器是否有可能理解重写的抽象类型
【发布时间】:2020-02-18 16:04:36
【问题描述】:

上下文:

我正在尝试在 RESTful 端点中使用 Jackson 提供的多态子类型 JsonSubTypes。各种请求主体之间存在一些共性,所以我有:

abstract class A extends Translatable {
  val infoA: String
  val infoB: String
}

case class B(
  infoA: String,
  infoB: String,
  infoC: String,
  infoD: Int
) extends A {
  override type T = B
  def translate(
    requestInfo: String,
    request: B
  ): String = s"<$infoA,$infoB>:$infoC-${infoD.toString}"
}


case class C(
  infoA: String,
  infoB: String,
  infoC: Array[String]
) extends A {
  override type T = C
  def translate(
    requestInfo: String,
    request: C
  ): String = s"<$infoA,$infoB>:${infoC.mkString}"
}

具有以下特征,因此无需将传入的A 请求与BC 进行模式匹配:

trait Translatable {
  type T <: A
  def translate(
    requestInfo: String,
    request: T
  ): String
}

问题是当我编译它抱怨类型不匹配:

found: request.type (with underlying type com.program.A)
required: request.T

我尝试了几件事,但无济于事,只有这个似乎接近了:

  • 隐式广义类型约束
e.g.,
def translate[X](
  requestInfo: String,
  request: X
)(implicit ev: X <:< A) = ...
(modifying the case class impl. of ^ accordingly)

但这会导致

无法证明 com.program.A <: request.t>

关于如何做到这一点的任何想法?还是我必须忍受模式匹配?我说是因为第一个代码块在我模式匹配并调用具体的 impl 时才有效。 translateBC,但我更愿意只使用 A 类型参数并在其上调用 translate。这可能吗?

编辑:添加上述产生编译错误的实例:

class Program {
  def doWork(
    info: String,
    request: A
  ): String = {
    request.translate(
      info,
      request // compilation fails/complains about this param in both cases
    )
  }
}

EDIT2:添加限定条件:我需要在子类型BC 中覆盖类型,以便在翻译函数中。我可以调用特定于BC 的字段

【问题讨论】:

  • "当我编译它抱怨类型不匹配" 编译什么?您能否更具体地说明哪条特定行会产生错误?以下代码编译没有错误:gist.github.com/DmytroMitin/eb059348c416dead20d7af7a47acfccd
  • 与@DmytroMitin 的结果相同
  • 抱歉,已更新示例
  • 更新了上面的BC,带有实际的实现。的翻译来强调为什么我需要覆盖类型 T。我需要能够访问特定于子类型的字段

标签: scala inheritance types jackson abstract


【解决方案1】:

尝试添加具有精细上限的类型参数

def doWork[T0 <: A { type T = T0 }](
            info: String,
            request: T0
          ): String = {
  request.translate(
    info,
    request
  )
}

doWork("info1", B("infoA1", "infoB1", "infoC1", 1))//<infoA1,infoB1>:infoC1-1
doWork("info2", C("infoA2", "infoB2", Array("infoC21", "infoC22")))//<infoA2,infoB2>:infoC21infoC22

【讨论】:

  • 鲍勃是你的叔叔!结构类型!我将不得不阅读更多关于这些的信息。这确实可以编译,尽管有 Scala 风格的抱怨,但我可以处理。谢谢!
  • @Mastergreek 更准确,更精细的类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 2018-10-22
  • 1970-01-01
  • 2017-05-04
  • 2019-02-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多