【问题标题】:How to avoid the use of asInstanceOf while passing data between modules in Scala如何在Scala中的模块之间传递数据时避免使用asInstanceOf
【发布时间】:2019-02-09 18:48:39
【问题描述】:

考虑以下情况:

class Program { }
object Program { }


object Generator{
    val program: Program = new Program

  def met = {
    val mychecker = Checker(program)
    mychecker.check
  }
}

trait Checker {
  val program: Program 
  def check
}

trait Order {
  val checker: Logic
  def met1: Nothing = checker.program
}

object Checker{
  def apply(p: Program) = new { 
    val program: p.type = p
  } with Logic { self =>
    object AnOrder extends {
      val checker: self.type = self     
    } with Order

    val order = AnOrder
  }

}

trait Logic extends Checker { self =>
  protected val order: Order { val checker: self.type }
  def check = order.met1
}

Generator.met

在这里,我写def met1: Nothing 是为了让你明白我的意思,基本上生成器和检查器的程序类型是不同的。所以我得到了

类型不匹配;找到:Order.this.checker.program.type(与 底层类型 Playground.this.Program) 需要:没有

现在,我的问题不是关于这个错误。我想问一下,当您有两个模块 M1 和 M2 时,如何避免使用 asInstanceOf 进行转换,其中一个将 T 类型的一些数据传递给 M2,M2 进行一些计算,然后返回相同的数据类型(直到这个差异,我们见错误)。

在上面的例子中你会怎么做?

现实世界的错误

正如我在我的一个 cmets 中所解释的那样,编译器不会通过更复杂的 Program 实例。例如,请参阅 my project,您无法使用 sbt -> compile 进行编译。您会看到由于这里提到的问题,terminationCache 给出了类型错误,我需要使用 asInstanceOf。

【问题讨论】:

  • 首先如果你可以定义你自己的类型,比如这个类型的程序。或者您可以使用案例类或案例对象,如果它不带任何参数。现在,如果您想使某种类型成为通用类型,那么您可以采取一些方法。最简单的方法是用空特征扩展它。
  • @RamanMishra 我不太清楚你的提议实际上是什么......
  • 你需要隔离问题,不清楚你的意思。路径相关类型被创建为不同的类型,但我在您的代码中看不到任何路径相关类型。
  • 请问投反对票的人也可以要求结束这个问题吗?
  • @BrianMcCutchon 不,因为已经有两个答案,帮助中心说在这种情况下我不能删除它!

标签: scala types


【解决方案1】:

我基本上忽略了您粘贴的代码,但要回答您在文本中提出的问题,您可以执行以下操作:

trait MyTrait {
  def someCommonMethod: Whatever
}

case class Something(foo: Int) extends MyTrait {
  def someCommonMethod: Whatever = ???
}

object M2 {
  def someComputation[T <: MyTrait](t: T): T = {
    //can call t.someCommonMethod in here if you want
    ???
  }
}

object M1 {
  def doSomething(something: Something): Something = {
    M2.someComputation(something)
  }
}

我不能 100% 确定这会回答您的问题,但希望对您有所帮助。

【讨论】:

  • 我不明白这如何回答我的问题。特别是,问题是M1.Program和M2.Program之间的区别以及如何统一对待它们
【解决方案2】:

我不明白这个问题。我认为您要么犯了一个单独的错误,并将您的错误归因于您在问题中描述的幻象症状,要么我误解了您。

这是您发布的代码的一个版本,在我看来与您的问题无关的细微调整,编译得很好 (try it here):

class Program { }
object Program { }
trait Logic {}


object Generator{
    val program: Program = new Program

  def met = {
    val mychecker = Checker(program)
    mychecker.check
  }
}

trait Checker {
  val program: Program 
  def check
}

trait Order {
  val checker: Checker
  def met1: Program = checker.program
}

object Checker{
  def apply(p: Program) = new { 
    val program: p.type = p
  } with Checker { self =>
    object AnOrder extends {
      val checker: self.type = self     
    } with Order

    val order = AnOrder

    def check = println("check here")
  }

}

println("compiled OK")

请注意,我已将def met1: Nothing 更改为def met1: Program,它工作正常。

你问:

当您有两个模块 M1 和 M2 时,如何避免使用 asInstanceOf 进行转换,其中一个将 T 类型的一些数据传递给 M2,M2 进行一些计算,然后返回完全相同的数据类型

我认为当两个模块 M1 和 M2 都与一个公共类型交互时,你不需要使用asInstanceOf,例如在这种情况下为Program

【讨论】:

  • 该错误只是表明类型 M1.Program 和 M2.Program 是不同类型的一种方式。这会导致我无法在 M2 中收集例如类型 Program.FunDef 并将其传递给 M1,因为 M1 将看到类型 M2.Program.FunDef 并且必须使用 asInstanceOf 将其转换为 M1.Program.FunDef。这就是我想解释的
  • M1.Program 和 M2.Program 不是不同的类型,如我的示例代码所示。他们都是同一个班级,Program
  • 您的代码编译的事实表明,对于这种简单的情况,编译器可以看到“基础类型”是相同的。但是,如果您通过将 Generator.program 分配给键入错误的变量来检查 Generator.program,它将检测到 Generator.program.type,如果您检查 met1 的输出,您将获得 Order.this.checker.program.type。这些是 afaik 两种不同的依赖于路径的类型,在实际应用程序中(我无法指向我的项目)可能无法检测到相等,因此需要使用 asInstanceOf 方法
  • @Rodrigo 然后发布一个实际说明您的问题的示例。
  • 正如之前的评论者所指出的,很难回答你的问题,因为你没有清楚地说明你的问题是什么。通过查看您的代码,我看到的唯一问题是代码看起来过于复杂,因为我没有看到使用 p.typeself.type 的理由(仅使用基本类型)或需要使用早期初始化器(注意它们将在 Scala 3 中消失)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-24
  • 2019-08-11
  • 1970-01-01
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多