当前位置: 首页 > 知识库问答 >
问题:

for构造中的scala模式匹配

宫修贤
2023-03-14

我有下面的数据模型,稍后我将对其进行模式匹配:

abstract class A
case class C(s:String) extends A

abstract class B extends A
case class D(i:Int) extends B
case class E(s:Int, e:Int) extends B

A是层次结构的抽象超类型。C是a的具体子类。a的其他具体子类是B的子类,B又是a的子类。

现在如果我写这样的东西,它是有效的:

def match(a:A) a match {
   a:C => println("C")
   a:B => println("B")
}

然而,在for循环中,我无法与B匹配。我假设我需要一个构造函数模式,但由于B是抽象的,所以B没有构造函数模式。

val list:List[A] = List(C("a"), D(1), E(2,5), ...)

for (b:B <- list) println(b)  // Compile error
for (b@B <- list) println(b)  // Compile error

这里,我只想打印B个实例。这个案子有解决办法吗?

共有3个答案

柳宏深
2023-03-14

如果你问我,你不能在这里使用模式匹配的事实是scala的一个不幸的不一致性。事实上,scala确实可以让您在理解上进行模式匹配,如本例所示:

val list:List[A] = List(C("a"), D(1), E(2,5)
for ((b:B,_) <- list.map(_ -> null)) println(b)

在这里,我暂时将元素包装成对(其中有一个虚拟的和未使用的第二个值),然后为第一个元素类型为B的一对进行模式匹配。

 D(1)
 E(2,5)

这样看来,scala确实支持基于模式匹配的过滤(即使是按类型匹配),只是语法似乎不处理按类型匹配单个元素的模式。

显然,我不是建议使用这个技巧,这只是为了说明。使用collect当然更好。

如果出于某种原因,你真的更喜欢理解,那么还有一个更普遍的解决方案:

object Value {
  def unapply[T]( value: T ) = Some( value )
}
for ( Value(b:B) <- list ) println(b)

我们刚刚在Value对象中引入了一个虚拟提取器,它什么也不做,因此Value(b:b)与justb:b具有相同的含义,只是前者进行编译。与我之前的配对技巧不同,它相对可读,而且Value只需编写一次,然后你就可以随意使用它(特别是,不需要为你想要匹配的每种类型编写一个新的提取器,如@Faiz的回答。不过,我会让你找到一个比Value更好的名称。

最后,还有一个现成的解决方案(归功于丹尼尔·索布拉尔),但可读性稍差,需要一个虚拟标识符(这里是foo):

for ( b @(foo:B) <- list ) println(b)
// or similarly:
for ( foo @(b:B) <- list ) println(b)
吴展
2023-03-14

谢尔盖是对的;如果你想进行模式匹配并只过滤B实例,你就必须放弃。如果出于任何原因,你仍然想使用进行理解,我认为一种方法就是使用警卫:

for (b <- list if b.isInstanceOf[B]) println(b)

但最好选择模式匹配,而不是isInstanceOf。因此,我会使用收集建议(如果它在我的其他代码中有意义的话)。

另一个建议是定义一个同名的B伴生对象,并定义unapply方法:

abstract class A
case class C(s:String) extends A

abstract class B extends A
object B { def unapply(b: B) = Option(b)  } // Added a companion to B
case class D(i:Int) extends B
case class E(s:Int, e:Int) extends B

然后你可以这样做:

for (B(b) <- list) println(b)

这不是B的“构造函数”,而是它的方法。这很有效,这就是朋友的作用,对吧?

(见http://www.scala-lang.org/node/112 )

欧阳向文
2023-03-14

可以使用收集

list.collect { case b: B => println(b) }

如果你想更好地理解这一点,我建议你阅读部分函数。这里举个例子。

 类似资料:
  • 主要内容:实例,实例,使用样例类,实例Scala 提供了强大的模式匹配机制,应用也非常广泛。 一个模式匹配包含了一系列备选项,每个都开始于关键字 case。每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。 以下是一个简单的整型值模式匹配实例: 实例 object Test {     def main (args : Array [String ] ) {       println (matchTes

  • Scala 提供了强大的模式匹配机制,应用也非常广泛。 一个模式匹配包含了一系列备选项,每个都开始于关键字 case。每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。 以下是一个简单的整型值模式匹配实例: object Test { def main(args: Array[String]) { println(matchTest(3))

  • 本文向大家介绍浅谈Scala模式匹配,包括了浅谈Scala模式匹配的使用技巧和注意事项,需要的朋友参考一下 一.scala模式匹配(pattern matching) pattern matching可以说是scala中十分强大的一个语言特性,当然这不是scala独有的,但这不妨碍它成为scala的语言的一大利器。 scala的pattern matching是类似这样的, 其中,变量e后面接一个

  • 本文向大家介绍Scala序列上的模式匹配,包括了Scala序列上的模式匹配的使用技巧和注意事项,需要的朋友参考一下 示例 检查集合中元素的准确数量 现场演示 提取first(s) element(s)并将其余部分保留为集合: 通常,可以用于构建序列的任何形式都可以用于与现有序列进行模式匹配。 请注意,在使用Nil和::在对序列进行模式匹配时将起作用,但确实会将其转换为List,并且可能会产生意外结

  • 假设我有一个普通的第三方(即我不能修改它)类,定义如下: 如何使用模式匹配实现?

  • 在面向对象编程中,构造器是一个当新建对象的内存被分配后,用来初始化该对象的一个特殊函数。在Javascript中几乎所有的东西都是对象,我们经常会对对象的构造器十分感兴趣。 对象构造器是被用来创建特殊类型的对象的,首先它要准备使用的对象,其次在对象初次被创建时,通过接收参数,构造器要用来对成员的属性和方法进行赋值。 对象创建 下面是我们创建对象的三种基本方式: // 下面的每一种都会创建一个新的对