我有一个非常简单的类。
case class Foo[+T](t: T)
现在我想添加一个参数来转换T到Int. 由于特殊的原因,我不想使用类型类、隐式或任何基于继承的解决方案,因为这才是我真正的建模:一个包含一些数据的类和转换数据的函数。
所以我写了
case class Foo[+T](t: T, f: T => Int)
或
case class Foo[+T](t: T, f: Function1[T, Int])
当然,这是行不通的,因为f在T上是反变的,有什么解决办法吗?
你可以尝试使用存在型
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)
.