如果我们暂时忘记模式匹配,可以在某种程度上使用普通的反射:
import reflect.ClassTag
trait Outer[S] {
type A1
def inner: Inner[S] { type A = A1 }
def as[A](implicit tag: ClassTag[A]): Option[Outer[S] { type A1 = A }] =
inner.peer match {
case _: A => Some(this.asInstanceOf[Outer[S] { type A1 = A }])
case _ => None
}
}
trait Inner[S] {
type A
def peer: A
}
测试:
trait Foo[S]
val x = new Outer[Unit] {
type A1 = String
val inner = new Inner[Unit] {
type A = String
val peer = "foo"
}
}
val y = new Outer[Unit] {
type A1 = Foo[Unit]
val inner = new Inner[Unit] {
type A = Foo[Unit]
val peer = new Foo[Unit] {}
}
}
val xs = x.as[String]
val xi = x.as[Foo[Unit]]
val ys = y.as[String]
val yi = y.as[Foo[Unit]]
现在唯一的问题是没有检查更高种类的类型:
y.as[Foo[Nothing]] // Some!
另一个想法是更改我的设计以要求S
参数始终存在。然后
trait Sys[S <: Sys[S]]
trait Inner[S <: Sys[S], +Elem[~ <: Sys[~]]] {
def peer: Elem[S]
def as[A[~ <: Sys[~]]](implicit tag: ClassTag[A[S]]): Option[Inner[S, A]] =
if (tag.unapply(peer).isDefined)
Some(this.asInstanceOf[Inner[S, A]])
else
None
}
type In[S <: Sys[S]] = Inner[S, Any]
trait Foo[S <: Sys[S]] { def baz = 1234 }
trait Bar[S <: Sys[S]]
trait I extends Sys[I]
val i: In[I] = new Inner[I, Foo] { val peer = new Foo[I] {} }
val j: In[I] = new Inner[I, Bar] { val peer = new Bar[I] {} }
assert(i.as[Foo].isDefined)
assert(i.as[Bar].isEmpty )
assert(j.as[Foo].isEmpty )
assert(j.as[Bar].isDefined)
或者最后一个版本改回使用类型成员:
trait Inner[S <: Sys[S]] {
type Elem
def peer: Elem
def as[A[~ <: Sys[~]]](implicit tag: ClassTag[A[S]]): Option[InnerT[S, A]] =
if (tag.unapply(peer).isDefined)
Some(this.asInstanceOf[InnerT[S, A]])
else
None
}
type InnerT[S <: Sys[S], A[~ <: Sys[~]]] = Inner[S] { type Elem = A[S] }
val i: Inner[I] = new Inner[I] { type Elem = Foo[I]; val peer = new Foo[I] {} }
val j: Inner[I] = new Inner[I] { type Elem = Bar[I]; val peer = new Bar[I] {} }
assert(i.as[Foo].isDefined)
assert(i.as[Bar].isEmpty )
assert(j.as[Foo].isEmpty )
assert(j.as[Bar].isDefined)
val ix: InnerT[I, Foo] = i.as[Foo].get
ix.peer.baz
...这可能有利于隐式解析,例如Serializer[Inner[S]]
在涉及变体类型参数时很容易破坏。