【问题标题】:Scala: Pattern matching a generic case class for "concrete" casesScala:模式匹配“具体”案例的通用案例类
【发布时间】:2017-04-25 12:19:04
【问题描述】:

假设我有:

sealed trait Data
final case class TextData()  extends Data
final case class ImageData() extends Data
final case class MetaData[D <: Data](data: D) extends Data

我想对 Data 对象进行模式匹配。我已经定义了:

def getDataTypeName(data: Data): String ={
    data match {
        case TextData()=>"text"
        case ImageData()=>"image"
        //MetaData(MetaData(_))=>"metaMeta1"  //a
        case _:MetaData[MetaData[_]]=>"metaMeta2"  //b
        //case MetaData(data:Data)=>"meta"+ getDataTypeName(data) //c
        //MetaData(TextData(_))=>"metaMeta1"  //d
        case MetaData(_)=>"meta"
    }
}

我希望能够查看我的数据是元元数据、元文本数据等。 线a给我一个错误,说:

构造函数不能被实例化为期望的类型;成立 : inst$A$A.MetaData[D] 需要:A$A115.this.Data 案例 MetaData(MetaData(_))=>"metaMeta1"

我希望有类似a 的东西。或者像c 这样的行也很好。

我也试过b。这会产生一些警告:

非变量类型参数 A$A115.this.MetaData[] in 类型模式 A$A115.this.MetaData[A$A115.this.MetaData[]] 是 未经检查,因为它被擦除消除 案例 :MetaData[MetaData[]]=>"metaMeta" ^

我收到了MetaData[_]s 的警告。我的理解是,在类型擦除后,上述模式被简化为 _,这与我的测试结果一致。

因此我想知道是否有办法匹配MetaMetaDataMetaTextDataMetaMetaMetaData 等。

或者,我的设计是否以不应该使用的方式使用密封类?你会建议什么替代设计?

【问题讨论】:

  • 我假设匹配元数据,然后再次匹配以检查内部类不是您理想的解决方案吗? data match { case Metadata(x) =&gt; x match { ... } }
  • 我想我也会很高兴。事实上,我确实尝试过做类似的事情(c 行),但语法不正确。

标签: scala types pattern-matching


【解决方案1】:

我对@9​​87654321@ 的定义进行了更改以使其正常工作。

sealed trait Data
final case class TextData()  extends Data
final case class ImageData() extends Data
final case class MetaData(data: Data) extends Data

def printType(data: Data): String = data match {
  case TextData()=>"text"
  case ImageData()=>"image"
  case MetaData(d)=>"meta:" + printType(d)
}

val md = MetaData( MetaData(TextData()) )
printType(md)  // res0: String = meta:meta:text

【讨论】:

  • 哦,我明白了。这让我想到:就编译器如何看待它而言,之前的定义和这个定义之间有什么真正的区别吗?
  • 好吧,显然编译器对它们的看法不同,因为这不会在原始定义下编译。它会对您的代码产生影响吗?可能不会。
  • 我想不同之处在于,在旧定义中,数据实际上是与之交互的,作为它的子类型,而在新格式中,它只是基类的一个实例。但这真的重要吗?不是真的。
【解决方案2】:
  sealed trait Data
  final case class TextData()  extends Data
  final case class ImageData() extends Data
  final case class MetaData[D <: Data](data: D) extends Data

def getDataTypeName(data: Data): String ={
    data match {
      case TextData()=>"text"
      case ImageData()=>"image"
      case MetaData(MetaData(_))=> "metaMeta1" 
      case MetaData(TextData())=> "textMeta1"  
      case MetaData(ImageData())=> "imgMeta1"  
    }
  }

在 REPL 上测试:

scala> getDataTypeName(TextData())
res1: String = text

scala> getDataTypeName(MetaData(TextData()))
res2: String = textMeta1

scala> getDataTypeName(MetaData(MetaData(TextData())))
res3: String = metaMeta1

【讨论】:

    猜你喜欢
    • 2014-08-12
    • 2017-02-25
    • 1970-01-01
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-28
    相关资源
    最近更新 更多