Рассмотрим следующие классы:Тип вывода и тип оценки в Scala
class Type { def +(other:Type):Type = this}
class SubType extends Type
Теперь я хочу, чтобы создать объект-оболочку, которая принимает бинарную функцию, работающего на Type
или его производных типов, давайте начнем с:
case class Fct(f:(Type,Type) => Type)
Я могу создать экземпляр класса Fct
с помощью _+_
применить метод, но я не могу передать функцию, используя Subtype
класс, который, как ожидается:
val f1 = Fct(_+_) // OK
val f2 = Fct((x:SubType,y:Type) => y) // error: found: (SubType, Type) => Type, required: (Type, Type) => Type
Теперь мы можем определить Fct
с помощью дженериков и оценки типа принимать подтипы:
case class Fct[T <: Type, U <: Type, V <: Type](f:(T,U) => V)
Теперь f2
работает так, как ожидалось, но f1
не действует больше, и я не понимаю, почему:
val f1 = Fct(_+_) // error: missing parameter type
val f2 = Fct((x:SubType,y:Type) => y) // OK
есть ли синтаксис, который будет принимать как f1
и f2
?
Редактировать
(ответить м-г) есть способ обойти вопросы вариантности с заводом? Что-то вроде:
class Fct(f:(Type,Type) => Type)
object Fct {
def apply(f:(Type,Type) => Type): Fct = new Fct(f)
def apply[T <: Type, U <: Type, V <: Type](f:(T,U) => V): Fct =
new Fct((x:Type,y:Type) => {(x,y) match {
case (a:T, b:U) => f(a,b)
case _ => ???
}}: Type)
}
Я надеялся обойти проблему отклонения с использованием заводского шаблона. Я добавил одну из моих попыток к вопросу, но синтаксис все еще не правильный. – Thibaut
@Thibaut Возможно, вы сможете получить это для компиляции, но вы будете лгать компилятору. 'Fct' будет считать, что в нем есть' (Type, Type) => Type', когда это не так.Это означает, что если вы передаете 'Type' в качестве одного из параметров, но на самом деле это подтип, вы получите исключение ClassCastException во время выполнения. –
Все было бы хорошо. Очевидно, что downcasts были менее грубыми, чем в моем примере, и я могу реализовать правильные проверки ошибок. Проблема убеждает систему типов, что позволяет мне это делать. – Thibaut