代码之家  ›  专栏  ›  技术社区  ›  Max A.

如何模式匹配大型案例类?

  •  38
  • Max A.  · 技术社区  · 15 年前

    考虑以下Scala案例类:

    case class WideLoad(a: String, b: Int, c: Float, d: ActorRef, e: Date)
    

    模式匹配允许我提取一个字段并丢弃其他字段,如下所示:

    someVal match {
        case WideLoad(_, _, _, d, _) => d ! SomeMessage(...)
    }
    

    我想做的是,当一个case类有20多个字段时,更相关的是,以一种不涉及键入的方式只提取几个值 WideLoad(_, _, _, _, _, some, _, _, _, thing, _, _, interesting)

    someVal match {
        case WideLoad(d = dActor) => dActor ! SomeMessage(...)
        //              ^---------- does not compile
    }
    

    这里还有希望吗?还是我被困在打字上太多太多了 _, _, _, _ ?

    编辑 case wl @ WideLoad(...whatever...) => wl.d val .

    3 回复  |  直到 15 年前
        1
  •  37
  •   Magnus    15 年前

    我不知道这是否合适,但您也可以构建一个对象来匹配该字段或该字段集(未测试的代码):

    object WideLoadActorRef {
      def unapply(wl: WideLoad): Option[ActorRef] = { Some(wl.d) }
    }
    
    someVal match {
      case WideLoadActorRef(d) => d ! someMessage
    }
    

    甚至

    object WideLoadBnD {
      def unapplySeq(wl: WideLoad): Option[(Int,ActorRef)] = { Some((wl.b,wl.d)) }
    }
    
    someVal match {
      case WideLoadBnD(b, d) => d ! SomeMessage(b)
    }
    
        2
  •  15
  •   Landei    15 年前

    你可以随时找警卫。这不是很好,但比正常模式匹配更好的怪物案例类:-P

    case class Foo(a:Int, b:Int, c:String, d:java.util.Date)
    
    def f(foo:Foo) = foo match {
      case fo:Foo if fo.c == "X" => println("found")
      case _ => println("arrgh!")
    }
    
    f(Foo(1,2,"C",new java.util.Date())) //--> arrgh!
    f(Foo(1,2,"X",new java.util.Date())) //--> found
    

    我觉得你应该重新考虑你的设计。可能您可以使用case类、元组、列表、集合或映射逻辑地将一些参数分组在一起。斯卡拉 支持嵌套模式匹配:

    case class Bar(a: Int, b:String)
    case class Baz(c:java.util.Date, d:String)
    case class Foo(bar:Bar, baz:Baz)
    
    def f(foo:Foo) = foo match {
       case Foo(Bar(1,_),Baz(_,"X")) => println("found")
       case _ => println("arrgh!")
    }
    
    f(Foo(Bar(1,"c"),Baz(new java.util.Date, "X"))) //--> found
    f(Foo(Bar(1,"c"),Baz(new java.util.Date, "Y"))) //--> arrgh! 
    
        3
  •  0
  •   vaer-k Dogbert    6 年前

    您只需在匹配的模式中指定类型:

    case class WideLoad(a: String, b: Int, c: Float, d: ActorRef, e: Date)
    
    val someVal = WideLoad(...)
    
    someVal match {
        case w: WideLoad => w.d ! SomeMessage(...)
    }
    
        4
  •  0
  •   Ian Purton RHT    6 年前

    您可以创建一个新的case类,它是较大case类的摘要

    case class WideLoad(a: String, b: Int, c: Float, d: ActorRef, e: Date)
    case class WideLoadSummary(d: ActorRef, e: Date)
    

    然后模式匹配正常。

    val someVal = WideLoadSummary(wideload.d, wideload.e)
    
    someVal match {
        case WideLoadSummary(d, _) => d ! SomeMessage(...)
    }
    
    推荐文章