#scala
#scala
Вопрос:
Предположим, у меня есть следующий класс Foo, который поддерживает функцию любой множественности, используя трюк с кортежем:
abstract class Foo[T, R] {
def pull: T => R
}
Я могу определить подкласс со следующим синтаксисом:
implicit def function2Tofunction1[T1, T2, R](f: (T1, T2) => R): ((T1, T2)) => R = {
f.tupled
}
class Moo extends Foo[(Int, Int), Int] {
def pullImpl(x: Int, y:Int):Int = x y
def pull = (pullImpl _) // implicit converts to tupled form
}
val m = new Moo()
m.pull(4, 5)
Это довольно неуклюже. Идеальный синтаксис был бы следующим:
class Moo extends Foo[(Int, Int), Int] {
def pullImpl(x: Int, y:Int):Int = x y
}
Есть ли какой-либо способ определить мой базовый класс таким образом, чтобы этого можно было достичь?
Ответ №1:
Если вы можете быть удовлетворены определением реализации как функции, а не метода, тогда это работает:
abstract class Foo[T, R] {
type Fn = T => R
val pull: Fn
}
class Moo extends Foo[(Int, Int), Int] {
// The type has to be explicit here, or you get an error about
// an incompatible type. Using a type alias saves typing out
// the whole type again; i.e. ((Int, Int)) => Int
lazy val pull: Fn = (x: Int, y: Int) => x y
}
В противном случае, я думаю, вам понадобится больше оборудования для поддержки сигнатур методов реализации для разных элементов:
trait Foo[T, R] {
type Fn = T => R
val pull: T => R
}
trait FooImpl2[T1, T2, R] extends Foo[(T1, T2), R] {
lazy val pull: Fn = (pullImpl _).tupled
protected def pullImpl(x: T1, y: T2): R
}
// similarly for FooImpl3, FooImpl4, ...
class Moo extends FooImpl2[Int, Int, Int] {
protected def pullImpl(x: Int, y: Int) = x y
}