Функции в Scala моделируются через трейт FunctionN
. Например, все простые функции с одним входом и одним выходом являются экземплярами следующего признака:
trait Function1[-T1, +R] extends AnyRef
Итак, вы спрашиваете: «Как я могу сделать экземпляры Function
также подклассами C
». Это невозможно сделать с помощью стандартного подтипа/наследования, потому что, очевидно, мы не можем изменить черту Function1
, чтобы она расширяла ваш пользовательский класс C
. Конечно, мы могли бы создать новый класс для представления функции, как вы предложили, но это только заведет нас так далеко, и это не так просто реализовать, не говоря уже о том, что любую функцию, которую вы хотите использовать как C
, придется преобразовать. сначала к вашей псевдофункциональной черте, что сделает все ужасно.
Что мы можем сделать, так это создать класс типов, который затем будет содержать реализацию для A -> B
, среди прочего.
В качестве примера возьмем следующий код:
trait A
trait B
trait C[T]
object C {
implicit val fa = new C[A] {}
implicit val fb = new C[B] {}
implicit val fab = new C[Function1[A, B]] {}
}
object Test extends scala.App {
val f: A => B = (a: A) => new B {}
def someMethod[Something: C](s: Something) = {
// uses "s", for example:
println(s)
}
someMethod(f) // Test$$$Lambda$6/1744347043@dfd3711
}
Вы не указали свою мотивацию для того, чтобы сделать A -> B расширением C, но, очевидно, вы хотите иметь возможность поместить A, B и A -> B под «одним и тем же зонтиком», потому что у вас есть, скажем, некоторый метод (называемый someMethod
), который принимает C
, поэтому при наследовании вы можете передавать ему значения типа A, B или A -> B.
С классом типов вы достигаете того же самого, но с некоторыми дополнительными преимуществами, такими как, например. добавление D
в семейство в один прекрасный день без изменения существующего кода (вам просто нужно реализовать неявное значение типа C[D]
где-то в области видимости).
Таким образом, вместо того, чтобы someMethod
принимал экземпляры C
, он просто берет что-то (назовем это s
) некоторого типа (назовем это Something
) с ограничением, что C[Something]
должно существовать. Если вы передадите что-то, для чего не существует экземпляра C, вы получите сообщение об ошибке:
trait NotC
someMethod(new NotC {})
// Error: could not find implicit value for evidence parameter of type C[NotC]
Вы достигаете того же самого — у вас есть семья из C
, членами которой являются A
, B
и A => B
, но вы обходите проблемы с подтипами.
person
slouc
schedule
15.01.2018