Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 通过匹配与类型成员对应的成员值来获取优化的类型_Scala_Pattern Matching_Type Members - Fatal编程技术网

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
进行class
Foo
的第一次调用的值并不意味着对
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
    类型定义隐式
    Processor
    s

我认为将隐式<代码>处理器 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