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