我有一个案例类,存储三个绑定参数。我想定义可以从任何两个参数构建类的伴随对象,看起来像下面的示例,这显然是不正确的:
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)
我可以用什么技巧来获得类似的用法语法?
答案 0 :(得分: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()
答案 1 :(得分: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)
个实例。
由于代码量很小,人们可能会定义一个宏来完成工作,但这对我来说现在有点困难,但这是一个有趣的练习。
更新
过了一段时间后,我想向您注意,您的案例中只有三种参数组合,因此手动提供3种apply()
方法不是更容易吗? apply(s, d), apply(s, e), apply(d, e)
应该满足您的需求。这将为您节省一些打字,因为使用其他方法,您基本上也必须编写所有这些案例。