Определить именованные аргументы по умолчанию в терминах других аргументов в scala

У меня есть класс 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)

Какие приемы я могу использовать, чтобы получить похожий синтаксис использования?

2 ответа

Решение

Вы можете использовать type-классы:

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

Подумав немного, я пришел с другим решением (я не утверждаю, что оно лучше, просто хотелось бы узнать, является ли это приемлемым подходом). Суть в том, чтобы определить класс: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) должно удовлетворить ваши потребности. И это избавит вас от необходимости печатать, потому что с другими подходами вам в основном приходится кодировать и все эти случаи.

Другие вопросы по тегам