Вы можете попробовать экзистенциальный тип
case class Foo[+T](t: T, f: (_ <: T) => Int)
, но на самом деле (_ <: T) => Int
это просто Nothing => Int
.
(в Dotty также возможно иметь case class Foo[+T](t: T, f: [U <: T] => U => Int)
.)
Рассмотрите возможность добавления еще одного параметра типа
case class Foo[+T, U <: T](t: T, f: U => Int)
Тогда вы можете использовать "частично примененный" шаблон, когда хотите, чтобы U
был выведен
def mkFoo[T] = new PartiallyApplied[T]
class PartiallyApplied[T] {
def apply[U <: T](t: T, f: U => Int) = Foo(t, f)
}
trait Parent
case class Child(i: Int) extends Parent
mkFoo[Parent](new Parent {}, (c: Child) => c.i)
Еще одна опция - это сделать U
членом типа
trait Foo[+T] {
type U <: T
val t: T
val f: U => Int
}
object Foo {
def apply[T, _U <: T](_t: T, _f: _U => Int): Foo[T] { type U = _U } = new Foo[T] {
override type U = _U
override val t: T = _t
override val f: U => Int = _f
}
def unapply[T](foo: Foo[T]): Option[(T, foo.U => Int)] = Some((foo.t, foo.f))
}
Возможно, ваш класс может быть
case class Foo[+T](t: T) {
def f[U >: T](t1: U): Int = ???
}
В противном случае это просто инвариант case class Foo[T](t: T, f: T => Int)
.