根据scala中的其他参数定义默认命名参数

根据scala中的其他参数定义默认命名参数,scala,named-parameters,Scala,Named Parameters,我有一个case类,它存储三个绑定的参数。我想定义可以从任意两个参数构建类的伴生对象,类似于下面的示例,这显然是不正确的: def test(start : Float = end - duration, duration : Float = end - start, end : Float = start + duration) { require( abs(start + duration - end) < epsilon ) ... } val t1 = test(start

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

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)
def测试(开始:浮点=结束-持续时间,持续时间:浮点=结束-开始,结束:浮点=开始+持续时间){
需要(abs(开始+持续时间-结束)

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

您可以使用类型类:

// 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()

经过一点思考,我想出了另一个解决方案(我不认为它更好,只是想知道它是否是可以接受的方法)。本质是定义一个类:
类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
}
因此,您可以执行
valk=Klass(x=5,y=6)(
并获取
valk
以引用
Klass(5,6,11)
实例

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

更新


过了一段时间,我想告诉您,您的案例中只有三种参数组合,因此手动提供3种
apply()
方法不是更容易吗<代码>应用(s,d),应用(s,e),应用(d,e)
应该满足您的需要。这将为您节省一些输入,因为使用其他方法,您基本上也必须对所有这些情况进行编码。

请注意,只有当您的参数具有不同的类型时,这才有效。由于Java兼容性,您不能像这样重载
apply
。(在Java中,参数名称不是公共接口的一部分)。