【问题标题】:Differentiate between Map[String,String] and Map[String,Object]区分 Map[String,String] 和 Map[String,Object]
【发布时间】:2020-07-23 23:29:31
【问题描述】:

我的项目中创建了两张不同的地图。我都使用了类型别名。

type alias1 = Map[String, ScalaObject]
type alias2 = Map[String, String]

我有一个匹配情况,我想区分这两者,因为需要在两者上进行不同的操作。

val obj: T = fromJson[T](jacksonMapper, json)

obj match {
  case _: alias1 => operation1()
  case _: alias2 => operation2()
  case _ => obj
}

知道如何区分这两者吗?

【问题讨论】:

  • 你不能,由于类型擦除,这两种类型在运行时(正在执行模式匹配的地方)成为同一个类。您可以使用简单的 ADTtypeclass
  • 你能举个例子吗?

标签: json scala jackson


【解决方案1】:

ADT 会为每个案例创建一个带有一些案例类的密封特征;所以一个用于 Map[String, String],另一个用于 Map[String, ScalaObject],您可以在案例类上进行模式匹配。
像这样:

sealed trait MyType extends Product with Serializable
final case class ObjMap(data: Map[String, ScalaObject]) extends MyType
final case class StrMap(data: Map[String, String]) extends MyType

val obj: MyType = ???
obj match {
  case ObjMap(_) => operation1()
  case StrMap(_) => operation2()
}

Typeclass 方法可能太复杂了。

【讨论】:

    【解决方案2】:

    理解为什么在运行时无法区分这两个映射的两个关键概念是

    • 类型擦除 其中编译时参数化类型 Map[String, String] 变为运行时类 Map
    • 模式匹配转换为运行时isInstanceOfasInstanceOf 调用

    考虑以下简化示例

    case class Foo[T](i: T) 
    
    val fooInt = Foo[Int](42)
    val fooStr = Foo[String]("")
    
    fooInt.isInstanceOf[Foo[String]]
    // val res0: Boolean = true
    

    注意isInstanceOf 如何在运行时无法检查编译时类型参数T 是什么,因此它无法区分fooIntfooStr。实际上,我们能做的最好的事情就是

    fooInt.isInstanceOf[Foo[_]]
    

    下划线_ 用于传达类型擦除的事实。

    接下来考虑以下模式如何匹配

    (fooInt: Any) match { case str: Foo[String] => "oops :(" }
    // val res1: String = oops :(
    

    实际上变成了类似

    if (fooInt.isInstanceOf[Foo[String]]) "oops :("
    

    再次由于类型擦除错误地评估为"oops :("

    另一种方法是在编译时尝试在丢弃类型参数之前尽可能多地进行操作。 Typeclasses 可以被认为是在类型擦除之前发生的一种编译时模式匹配。

    【讨论】:

      猜你喜欢
      • 2020-08-01
      • 1970-01-01
      • 2018-09-22
      • 2020-01-26
      • 2013-05-24
      • 2014-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多