【问题标题】:Scala - Pattern matching - Is it possible to detect if value is a case class?Scala - 模式匹配 - 是否可以检测值是否为案例类?
【发布时间】:2017-12-23 08:13:50
【问题描述】:

我使用模式匹配来发现我的属性类型,如下所示:

value match {
    case s: String => processString(s)
    case l: Long => processLong(l)
    case c1: myCaseClass1 => processCaseClass(c1)
    case c2: myCaseClass2 => processCaseClass(c2)
    case c3: myCaseClass3 => processCaseClass(c3)
    case _ => nothingToDo
}

是否可以在不枚举我所有的案例类的情况下检测 value 是否是案例类?

【问题讨论】:

  • 您似乎在问一个错误的问题......想要这样做的原因可能是什么?您真正想在这里做什么? processCaseClass 是如何定义的?
  • 我喜欢有一个解释如何做的答案和另一个解释为什么不能做的答案的问题,尤其是当他们都被赞成的时候。

标签: scala pattern-matching


【解决方案1】:

默认情况下,每个案例类和元组都扩展 Product 特征。因此,您可以使用 Product 来捕获案例类和元组。警告:这可能会将普通类视为案例类,以防普通扩展 Product 特征。

value match {
  case _: Product => //catches all the case class values with tuple values also.
}

如果您只想捕获案例类,那么

value match {
  case x: Product if !x.getClass.getName.startsWith("scala.Tuple") =>
    //catches all the case classes.
}

Scala REPL

scala> case class Dog(name: String)
defined class Dog

scala> case class Cat()
defined class Cat

scala> val value = Dog("foo")
value: Dog = Dog(foo)

scala> value match { case _: Product => println("caught") }
caught

scala> val value = Cat()
value: Cat = Cat()

scala> value match { case _: Product => println("caught") }
caught

【讨论】:

  • 这也将捕获所有元组,每个元组不是案例类。
  • 这会错误地将以下类识别为案例类:class Foo(i: Int) extends Product1[Int] { override def _1 = i; override def canEqual(that: Any) = true }
【解决方案2】:

不,这是不可能的。案例类仅包含一些编译器生成的成员并具有编译器生成的伴随对象,但是无论如何您都可以手动实现。不可能区分实现相同成员的案例类和非案例类。 The Scala Language Specification 甚至包括编译器生成的成员的精确扩展。

您可以手动编写一个行为完全类似于案例类的类,并且无法区分它们。

【讨论】:

    【解决方案3】:

    如果这是在通用上下文中,您可以使用TypeTag 获取有关传入值类型的更多信息:

    scala> :pa
    // Entering paste mode (ctrl-D to finish)
    
    import scala.reflect.runtime.universe.{TypeTag, symbolOf}
    
    def foo[T: TypeTag](foo: T) =
      if (symbolOf[T].isClass && symbolOf[T].asClass.isCaseClass)
        println("It's a case class!")
      else
        println("Nope :(")
    
    // Exiting paste mode, now interpreting.
    
    
    scala> case class Foo(a: Int)
    defined class Foo
    
    scala> foo(Foo(3))
    It's a case class!
    
    scala> foo("bar")
    Nope :(
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-25
      • 2019-09-26
      • 2020-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-12
      • 1970-01-01
      相关资源
      最近更新 更多