7

我有一个存储三个绑定参数的案例类。我想定义可以从任何两个参数构建类的伴随对象,类似于下面的示例,这显然是不正确的:

def test(start : Float = end - duration, duration : Float = end - start, end : Float = start + duration) {
  require( abs(start + duration - end) < epsilon )
  ...
}
val t1 = test(start = 0f, duration = 5f)
val t2 = test(end = 4f, duration = 3f)
val t3 = test(start = 3f, end = 5f)

我可以使用什么技巧来获得类似的使用语法?

4

2 回答 2

26

您可以使用类型类:

// Represents no argument
object NoArg

// Resolves start, duration, stop
trait DurationRes[A,B,C] {
  def resolve(s: A, d: B, e: C): (Float, Float, Float)
}

object DurationRes {
  implicit object startEndRes extends DurationRes[Float, NoArg.type, Float] {
    def resolve(s: Float, d: NoArg.type, e: Float) = (s, e-s, e)
  }
  implicit object startDurRes extends DurationRes[Float, Float, NoArg.type] {
    def resolve(s: Float, d: Float, e: NoArg.type) = (s, d, s+d)
  }
  // etc.
}

def test[A,B,C](start: A = NoArg, dur: B = NoArg, end: C = NoArg)
               (implicit res: DurationRes[A,B,C]) {
  val (s,d,e) = res.resolve(start, dur, end)
  // s is start, d duration, e end
}

test(start = 1f, end = 2f)

这样它甚至是类型安全的,你不能调用类似的东西:

test(start = 1f)

甚至

test()
于 2013-08-12T22:10:45.520 回答
3

经过一番思考,我提出了另一种解决方案(我并没有声称它更好,只是想知道它是否是可以接受的方法)。本质是定义一个类: class Klass(val x: Int, val y: Int, val z: Int) 和一个伴生对象:

object Klass {
  def apply(x: Int, y: Int)(z: Int = x + y) = {
    new Klass(x, y, z)
  }
  // and so on
}

所以你可以做val k = Klass(x = 5, y = 6)()val k参考Klass(5, 6, 11)实例。

并且由于代码量小,可能可以定义一个宏来完成这项工作,但这对我来说有点困难,但这是一个有趣的练习。

更新

一段时间后,我想提醒您,您的情况只有三种参数组合,那么apply()手动提供三种方法不是更容易吗?apply(s, d), apply(s, e), apply(d, e)应该可以满足您的需求。这将为您节省一些打字,因为使用其他方法您基本上也必须编写所有这些情况。

于 2013-08-13T13:48:15.260 回答