Scala - 模式匹配相关类型的元组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11986892/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 04:27:07  来源:igfitidea点击:

Scala - pattern-matching a tuple of related types

scalapattern-matchingtuples

提问by noncom

I have the following class hierarchy:

我有以下类层次结构:

class A
class B extends A
class C extends A

then, there is another class which takes instances of these classes and there is a method, in which two cases of pattern-matching are possible like this:

然后,还有另一个类接受这些类的实例,并且有一个方法,其中可能有两种模式匹配,如下所示:

class D (one: A, two: A) {

  def work {
    (one, two) match {
      case (o, t): (B, B) => ... blablabla
      case (o, t): (B, C) => ... blablabla
      case _ =>
    }
  }
}

However, when it should resolve the matching in favor of the second case (B, C), it tries resolving it as (B, B)and comes up with the class cast exception that C cannot be cast to B. Why? What to do? How can I come around this?

但是,当它应该解析匹配以支持第二种情况时(B, C),它会尝试将其解析为 as(B, B)并提出类转换异常 that C cannot be cast to B。为什么?该怎么办?我怎样才能解决这个问题?

回答by Brian Smith

Your syntax isn't quite right (doesn't compile).

您的语法不太正确(无法编译)。

This works though:

这虽然有效:

object Matcher extends App {

  class A
  class B extends A
  class C extends A

  class D(one: A, two: A) {

    def work {
      (one, two) match {
        case (o: B, t: B) => println("B")
        case (o: B, t: C) => println("C")
        case _ =>
      }
    }
  }

  val d1 = new D(new B, new B)
  val d2 = new D(new B, new C)

  d1.work
  //B
  d2.work
  //C
}

回答by Submonoid

The problem, as always, is erased types. (B,C)is syntactic sugar for Tuple2[B,C], which is erased to Tuple2at runtime. The case statement verifies that (B,C)matches Tuple2, but then fails to cast it.

与往常一样,问题是擦除类型。(B,C)是 的语法糖Tuple2[B,C],它Tuple2在运行时被擦除。case 语句验证(B,C)匹配Tuple2,但随后无法转换它。

In your case, the easiest solution would be to match against 'one' and 'two' individually, rather than wrapping them in a tuple:

在您的情况下,最简单的解决方案是分别匹配“一”和“二”,而不是将它们包装在一个元组中:

one match {
  case o : B => two match {
    case p : C => ...
    case p : B => ...
  }
  ... 
}

It's not so pretty, but it won't suffer from the same problems.

它不是那么漂亮,但它不会遇到同样的问题。

Edit: Actually, I'd go with Brian Smith's solution - matching inside the tuple rather than outside. It avoids the problem in a similar way, but looks nicer.

编辑:实际上,我会采用 Brian Smith 的解决方案 - 在元组内部而不是外部匹配。它以类似的方式避免了这个问题,但看起来更好。

回答by tgr

I made this code work.
Firstly I added a case to your class definition.

我让这段代码工作。
首先,我在您的类定义中添加了一个案例。

case class A
case class B extends A
case class C extends A

Secondly I changed the work.

其次,我改变了work.

class D(one: A, two: A) {
  def work {
    (one, two) match {
      case (o: B, t: B) => println("BB")
      case (o: B, t: C) => println("BC")
      case (o: C, t: C) => println("CC")
      case _ => println("AA")
    }
  }
}

Now what I got:

现在我得到了什么:

new D(B(),B()).work      => BB
new D(B(),C()).work      => BC
new D(C(),C()).work      => CC
new D(A(),B()).work      => AA

The caseadds an apply and an unapply method.

case增加了一个适用和不应用方法。