Scala 通过匹配与类型成员对应的成员值来获取优化的类型
我有一个用于异构类型的容器Scala 通过匹配与类型成员对应的成员值来获取优化的类型,scala,pattern-matching,type-members,Scala,Pattern Matching,Type Members,我有一个用于异构类型的容器 trait Elem trait Obj { type E <: Elem def elem: E } trait Foo extends Elem 摆脱演员阵容的好主意是什么?理想情况下,它将作为模式匹配工作 例如,我可以创建单个提取器: object IsFoo { def unapply(obj: Obj): Option[Obj { type E = Foo }] = if (obj.elem.isInstanceOf[Foo
trait Elem
trait Obj {
type E <: Elem
def elem: E
}
trait Foo extends Elem
摆脱演员阵容的好主意是什么?理想情况下,它将作为模式匹配工作
例如,我可以创建单个提取器:
object IsFoo {
def unapply(obj: Obj): Option[Obj { type E = Foo }] =
if (obj.elem.isInstanceOf[Foo]) Some(obj.asInstanceOf[Obj { type E = Foo }])
else None
}
def test(obj: Obj): Unit = obj match {
case IsFoo(x) => withFooObj(x)
case _ =>
}
但是我有很多Elem
的子类型,我更希望有一个通用的提取器
Edit:由于这似乎是一个困难的问题,我想添加另一个放松:允许将
Obj
更改为包含类型参数而不是类型成员(如果有帮助的话)。不允许要求Obj
的子类,我认为这是不可能的。考虑(假设代码>类Foo扩展EELM < /代码>)
由于obj.elem
确实匹配f:Foo
,但是obj1
实际上没有类型obj{type E=Foo}
,因此您必须强制转换。在这种情况下,此强制转换实际上是安全的,但这仅仅是因为Obj
没有任何方法,例如采取e
的方法。实际上,这是不安全的,因为对elem
进行classFoo
的第一次调用的值并不意味着对elem
的所有调用都将返回Foo
编辑:如果您只需要在提取器中隐藏演员阵容就可以了,您可以执行以下操作:
case class IsElem[T <: Elem]()(implicit ct: ClassTag[T]) {
def unapply(obj: Obj): Option[Obj { type E = T }] =
if (ct.runtimeClass.isInstance(obj.elem)) Some(obj.asInstanceOf[Obj { type E = T }])
else None
}
val IsFoo = IsElem[Foo]
val IsBar = IsElem[Bar]
...
显然,这无助于安全问题。(我想聪明一点:)
trait思想{
定义解析[A](对象:对象)
(f:Function1[(Obj{typee=E1},E1)用于某些{typee1和fooobj(x)
案例=>
}
但是Scalac并不认为,
E1==Foo
这里…我将关注您对异构容器的需求,而忽略某些细节,如类型成员和模式匹配
摘要
目标是根据elem
类型找到某种方法来处理Obj
。工作解决方案的重要部分:
- 使
成为一个抽象类,它采用表示Obj
的类型参数elem
- 通过使用隐式参数,自动关联在与
相同类型上参数化的元素
处理器
- 为所有要使用的
类型定义隐式Elem
sProcessor
我认为将隐式<代码>处理器 s定义为最小的样板(如果你可以把它称为样板)。你需要定义<代码> EELM < /C> >特定的处理器,所以这些隐式对象是组织它们的好地方。
代码:trait Elem {
// for debugging only
def typeName: String
}
abstract class Obj[E <: Elem](implicit val processor: Processor[E]) {
def elem: E
def process(): Unit = processor.process(this)
}
trait Processor[R <: Elem] {
def process(obj: Obj[R]): Unit
}
object Processor {
implicit val fooProcessor = new Processor[Foo] {
def process(obj: Obj[Foo]): Unit = println(s"Processing Foo: ${obj.elem.typeName}")
}
implicit val barProcessor = new Processor[Bar] {
def process(obj: Obj[Bar]): Unit = println(s"Processing Bar: ${obj.elem.typeName}")
}
implicit val widgetProcessor = new Processor[Widget] {
def process(obj: Obj[Widget]): Unit = println(s"Processing Widget: ${obj.elem.typeName}")
}
}
trait Foo extends Elem { def typeName = "Foo" }
trait Bar extends Elem { def typeName = "Bar" }
trait Widget extends Elem { def typeName = "Widget" }
def test2[R <: Elem](obj: Obj[R]): Unit = obj.process()
// MAIN
val objFoo = new Obj[Foo] {
def elem: Foo = new Foo { }
}
println("===== test2 on a static-typed Foo")
test2(objFoo)
val objBar = new Obj[Bar] {
def elem: Bar = new Bar { }
}
println("===== test2 on a static-typed Bar")
test2(objBar)
val objWidget = new Obj[Widget] {
def elem: Widget = new Widget { }
}
println("===== test2 on a static-typed Widget")
test2(objWidget)
println("===== test2 on a heterogeneous list of `Obj`s")
val heteroList = List(objFoo, objBar, objWidget)
heteroList.foreach(test2(_))
好的,但是我可以在一些提取器函数中隐藏丢弃吗?毕竟模式匹配一直都在使用“安全”的丢弃。我有一个类似的想法,但当我不能执行
case-IsElem[Foo](x)时放弃了=>…
一次性存储。将它们存储为val
s当然是个好主意,因此没有额外的性能税。好的,谢谢。实际上合同是Elem
是稳定的,我还可以将其定义为val
。未选中的
是可以的,但在使用站点代码时不好。我将使用类似于IsElem
extractor。我越是关注这些问题,就越觉得动态类型语言在表示异构数据集合(编译时未知)时最终会成功。
case class IsElem[T <: Elem]()(implicit ct: ClassTag[T]) {
def unapply(obj: Obj): Option[Obj { type E = T }] =
if (ct.runtimeClass.isInstance(obj.elem)) Some(obj.asInstanceOf[Obj { type E = T }])
else None
}
val IsFoo = IsElem[Foo]
val IsBar = IsElem[Bar]
...
(obj, obj.elem) match {
case (obj: Obj[Foo] @unchecked, f: Foo) => ...
case (obj: Obj[Bar] @unchecked, f: Bar) => ...
}
trait Idea {
def resolve[A](obj: Obj)
(f: Function1[(Obj { type E = E1 }, E1) forSome { type E1 <: Elem }, A]): A
}
def test(obj: Obj, idea: Idea): Unit = idea.resolve(obj) {
case (x, _: Foo) => withFooObj(x)
case _ =>
}
trait Elem {
// for debugging only
def typeName: String
}
abstract class Obj[E <: Elem](implicit val processor: Processor[E]) {
def elem: E
def process(): Unit = processor.process(this)
}
trait Processor[R <: Elem] {
def process(obj: Obj[R]): Unit
}
object Processor {
implicit val fooProcessor = new Processor[Foo] {
def process(obj: Obj[Foo]): Unit = println(s"Processing Foo: ${obj.elem.typeName}")
}
implicit val barProcessor = new Processor[Bar] {
def process(obj: Obj[Bar]): Unit = println(s"Processing Bar: ${obj.elem.typeName}")
}
implicit val widgetProcessor = new Processor[Widget] {
def process(obj: Obj[Widget]): Unit = println(s"Processing Widget: ${obj.elem.typeName}")
}
}
trait Foo extends Elem { def typeName = "Foo" }
trait Bar extends Elem { def typeName = "Bar" }
trait Widget extends Elem { def typeName = "Widget" }
def test2[R <: Elem](obj: Obj[R]): Unit = obj.process()
// MAIN
val objFoo = new Obj[Foo] {
def elem: Foo = new Foo { }
}
println("===== test2 on a static-typed Foo")
test2(objFoo)
val objBar = new Obj[Bar] {
def elem: Bar = new Bar { }
}
println("===== test2 on a static-typed Bar")
test2(objBar)
val objWidget = new Obj[Widget] {
def elem: Widget = new Widget { }
}
println("===== test2 on a static-typed Widget")
test2(objWidget)
println("===== test2 on a heterogeneous list of `Obj`s")
val heteroList = List(objFoo, objBar, objWidget)
heteroList.foreach(test2(_))
===== test2 on a static-typed Foo
Processing Foo: Foo
===== test2 on a static-typed Bar
Processing Bar: Bar
===== test2 on a static-typed Widget
Processing Widget: Widget
===== test2 on a heterogeneous list of `Obj`s
Processing Foo: Foo
Processing Bar: Bar
Processing Widget: Widget