1

我是 Scala 的新手,我正在尝试使用类型边界来避免以下代码中的代码重复(从不相关的东西中清除):

trait StandardStep1[-I1] {
  def next_step(i:I1):StandardStep2
}

trait StandardStep2

trait UniqueStep1[-I1] extends StandardStep1[I1] {
  def next_step(i:I1):UniqueStep2
}

trait UniqueStep2 extends StandardStep2

class DoubleStandardStep1[-IL,-IR](left:StandardStep1[IL], right:StandardStep1[IR]) extends StandardStep1[(IL,IR)] {
  def next_step(i:(IL,IR)) = {
    val (i_left, i_right) = i
    val new_left = left.next_step(i_left)
    val new_right = right.next_step(i_right)
    new DoubleStandardStep2(new_left, new_right)
  }
}

class DoubleStandardStep2(left:StandardStep2, right:StandardStep2) extends StandardStep2

class DoubleUniqueStep1[-IL,-IR](left:UniqueStep1[IL], right:UniqueStep1[IR]) extends UniqueStep1[(IL,IR)] {
  def next_step(i:(IL,IR)) = {
    val (i_left, i_right) = i
    val new_left = left.next_step(i_left)
    val new_right = right.next_step(i_right)
    new DoubleUniqueStep2(new_left, new_right)
  }
}

class DoubleUniqueStep2(left:UniqueStep2, right:UniqueStep2) extends UniqueStep2

解释:

StandardStep1表示某个状态机中的一个步骤,并且有一个针对给定输入next_step给出 a 的操作。StandardStep2

UniqueStep1是一种特殊类型,当它被调用时会StandardStep1给出一个- 显然必须从中继承。UniqueStep2next_stepUniqueStep2StandardStep2

现在我必须编写一个DoubleStep包装器:DoubleStandardStep1包装太StandardStep1s,并在调用DoubleStandardStep2它时返回 a next_stepDoubleUniqueStep1做同样的事情,但它返回一个DoubleUniqueStep2.

*DoubleStep*s' 的实现next_step有一个明显的代码重复:它们都将输入拆分为i_left并以相同的方式i_right调用它们的包装步骤。next_step

我想知道如何通过创建一个通用抽象DoubleStep1来完成这部分代码,从而消除这种代码重复:

object DoubleStepHelper {
  def next_step_args[IL,IR,SL <: StandardStep1[IL],SR <: StandardStep1[IR]](left:SL,right:SR)(i:(IL,IR)) = { 
    val (i_left, i_right) = i
    val new_left = left.next_step(i_left)
    val new_right = right.next_step(i_right)
    (new_left, new_right)
  }
}

class DoubleStandardStep1[-IL,-IR](left:StandardStep1[IL], right:StandardStep1[IR]) extends StandardStep1[(IL,IR)] {
  def next_step(i:(IL,IR)) = {
    ((l,r) => new DoubleStandardStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i))
  }
}

class DoubleStandardStep2(left:StandardStep2, right:StandardStep2) extends StandardStep2


class DoubleUniqueStep1[-IL,-IR](left:UniqueStep1[IL], right:UniqueStep1[IR]) extends UniqueStep1[(IL,IR)] {
  def next_step(i:(IL,IR)) = {
    ((l,r) => new DoubleUniqueStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i))
  }
}

class DoubleUniqueStep2(left:UniqueStep2, right:UniqueStep2) extends UniqueStep2

尝试编译此代码(scala 2.9.2)失败并显示以下消息:

类型不匹配;
 找到:(this.StandardStep2,this.StandardStep2)
 必需:(this.UniqueStep2,this.UniqueStep2)
    ((l,r) => new DoubleUniqueStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i))
                                                                                            ^

我假设发生这种情况是因为DoubleStepHelper.next_step_args假设返回一个(StandardStep2, StandardStep2)值,当我们想用DoubleUniqueStep2.

你能想出解决这个问题的方法吗?如何告诉编译器DoubleStepHelpernext_step_args 可能返回一个(UniqueStep2, UniqueStep2)ifSLSR继承自UniqueStep1

一个不错的功能可能是能够将结果类型定义为(SL.next_step, SR.next_step)next_step_args之类的东西,这意味着它的返回类型是根据 和 中特定函数 ( next_step )的返回类型构建的。SLSR

“视图”边界可以以任何方式解决它吗?

我可以使用asInstanceOf强制转换,但这看起来很难看。

谢谢

4

1 回答 1

0

我找到了一个不错的解决方案。我创建AbstractStep1AbstractDoubleStep1在其中将以下步骤的类型作为类型参数给出。

然后我可以从这个类继承下一步是StandardStep2or的情况UniqueStep2

所以这里是代码:

trait AbstractStep1[-I,+S2] {
  def next_step(i:I):S2
}

trait StandardStep1[-I] extends AbstractStep1[I,StandardStep2]

trait StandardStep2

trait UniqueStep1[-I] extends AbstractStep1[I,UniqueStep2] with StandardStep1[I]

trait UniqueStep2 extends StandardStep2

abstract class AbstractDoubleStep1[-IL,-IR,-S2L <: StandardStep2,-S2R <: StandardStep2,+S2](left:AbstractStep1[IL,S2L],right:AbstractStep1[IR,S2R]) extends AbstractStep1[(IL,IR),S2] {
  def wrapper(l:S2L,r:S2R):S2

  def next_step(i:(IL,IR)):S2 = {
    val (i_left, i_right) = i
    val new_left = left.next_step(i_left)
    val new_right = right.next_step(i_right)
    wrapper(new_left, new_right)
  }
}

class DoubleStandardStep1[-IL,-IR](left:StandardStep1[IL], right:StandardStep1[IR]) extends AbstractDoubleStep1[IL,IR,StandardStep2,StandardStep2,DoubleStandardStep2](left,right) {
  def wrapper(l:StandardStep2,r:StandardStep2) = {
    new DoubleStandardStep2(l,r)
  }
}

class DoubleStandardStep2(left:StandardStep2, right:StandardStep2) extends StandardStep2


class DoubleUniqueStep1[-IL,-IR](left:UniqueStep1[IL], right:UniqueStep1[IR]) extends AbstractDoubleStep1[IL,IR,UniqueStep2,UniqueStep2,DoubleUniqueStep2](left,right) {
  def wrapper(l:UniqueStep2,r:UniqueStep2) = {
    new DoubleUniqueStep2(l,r)
  }
}

class DoubleUniqueStep2(left:UniqueStep2, right:UniqueStep2) extends UniqueStep2

我认为也可以转换AbstractDoubleStep1triat而不是abstract class,这将使其在 mixin 继承中更有用,但这对我来说目前并不重要。

于 2012-10-05T01:29:43.007 回答