我使用Rex Kerr's variant Miles Sabin's idea来在Scala中实现未装箱的联合类型。我有以下课程:
class Foo[T] {
trait Contr[-A] {}
type Union[A,B] = {type Check[Z] = Contr[Contr[Z]] <:< Contr[Contr[A] with Contr[B]]}
def foo[U: Union[T,Foo[T]]#Check](x:U) = x match {
case _: Foo[T] => println("x is a Foo[T]")
case _: T @unchecked => println("x is a T")
}
}
这允许以下内容:
val aux = new Foo[Int]
aux.foo(aux) // prints "x is a Foo[T]"
aux.foo(42) // prints "x is a T"
aux.foo("bar") // does not compile
然而:
val bar = new Foo[Foo[Int]]
bar.foo(bar) // OK: prints "x is a Foo[T]"
bar.foo(aux) // Not OK: prints "x is a Foo[T]"
有没有办法解决这个问题,也可能会消除@unchecked
?
修改
我认为这个特定示例的Union
类型可以简化为:
type Union[Z] = Contr[Contr[Z]] <:< Contr[Contr[T] with Contr[Foo[T]]]
然后foo函数可以是:
def foo[U: Union](x:U) = ...
这使代码更简单。但问题仍然存在。
答案 0 :(得分:0)
我提出了以下内容,它似乎有效,并且更接近我的实际用例:
import scala.reflect.runtime.universe._
case class Foo[T](z:T)(implicit tt:TypeTag[T], ft:TypeTag[Foo[T]]) {
trait Contr[-A]
type Union[Z] = Contr[Contr[Z]] <:< Contr[Contr[T] with Contr[Foo[T]]]
def foo[U: Union](x:U)(implicit tu:TypeTag[U]):T = tu.tpe match {
case t if t =:= tt.tpe => x.asInstanceOf[T]
case t if t =:= ft.tpe => x.asInstanceOf[Foo[T]].z
}
}
现在,以下效果很好:
val aux = new Foo[Int](42)
val bar = new Foo[Int](7)
val foobar = new Foo[Foo[Int]](bar)
println(aux.foo(aux)) // 42
println(aux.foo(1)) // 1
println(foobar.foo(aux)) // Foo(42)
println(foobar.foo(foobar)) // Foo(7)
我很高兴摆脱x.asInstanceOf
。