【发布时间】:2012-10-04 19:36:12
【问题描述】:
我是 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 操作,它为给定的输入提供一个StandardStep2。
UniqueStep1 是 StandardStep1 的一种特殊类型,它在调用 next_step 时给出 UniqueStep2 - 显然 UniqueStep2 必须从 StandardStep2 继承。
现在我必须编写一个 DoubleStep 包装器:DoubleStandardStep1 也包装 StandardStep1s,并在调用其 next_step 时返回一个 DoubleStandardStep2。
DoubleUniqueStep1 做同样的事情,但它返回一个 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 包装它时这是不好的。
你能想出解决这个问题的方法吗?如果SL和SR继承自UniqueStep1,如何告诉编译器DoubleStepHelper的next_step_args可能返回(UniqueStep2, UniqueStep2)?
一个不错的功能是能够将 next_step_args 的结果类型定义为类似 (SL.next_step, SR.next_step) 的东西,这意味着它的返回类型是从返回构建的SL 和 SR 中的特定函数类型(next_step)。
“视图”边界能以任何方式解决它吗?
我可以使用 asInstanceOf 强制转换,但这看起来很难看。
谢谢
【问题讨论】:
标签: scala design-patterns code-duplication