【问题标题】:Scala + pattern matching + String autoboxing [duplicate]Scala + 模式匹配 + 字符串自动装箱 [重复]
【发布时间】:2016-05-13 16:16:52
【问题描述】:

我报告了一个听起来很奇怪的功能,并且无法通过 scala 中的模式匹配来推断以下行为。

def typesPattern(x:Any)= x match{
    case s:String⇒ s.length
    case n:Map[Int,Int]⇒println("Map[Int,Int]");var a =  n.iterator.next();println(a._1);println(a._2);n.size;      
    case n:Map[a,b]⇒println("Map[a,b]");n.size;     
    case m:Map[_,_]⇒ m.size
    case _ ⇒ -1

    }
}

当我使用以下println(typesPattern(Map("a"→10))) 调用上述函数时,我收到以下错误Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101) at scala.Tuple2._1$mcI$sp(Tuple2.scala:20)

我的

第一个问题是“为什么 MAP[String->Int] 与 MAP[INT,INT] 匹配?”,它应该相当匹配MAP[_,_]

有趣的是,当我编辑模式匹配代码并取出从 Map 中提取元组并打印键值对的代码时

`def typesPattern(x:Any)= x match{
        case s:String⇒ s.length
        case n:Map[Int,Int]⇒println("Map[Int,Int]");n.size;     
        case n:Map[a,b]⇒println("Map[a,b]");n.size;     
        case m:Map[_,_]⇒ m.size
        case _ ⇒ -1

        }
    }`

现在,与之前的 println(typesPattern(Map("a"→10))) 相同的调用确实匹配 MAP[INT,INT] 没有问题并打印大小。

Map[Int,Int] 
    1

第二个问题 “为什么这次 SCALA 能够毫无问题地匹配 MAP[String->INT] 和 MAP[INT->INT](我仍然想知道如何?)?

【问题讨论】:

    标签: scala pattern-matching


    【解决方案1】:

    您可能尝试查看编译器给您的警告?

    <console>:12: warning: non-variable type argument Int in type pattern scala.collection.immutable.Map[Int,Int] (the underlying of Map[Int,Int]) is unchecked since it is eliminated by erasure
           case n:Map[Int,Int]⇒println("Map[Int,Int]");var a =  n.iterator.next();println(a._1);println(a._2);n.size;
                  ^
    <console>:13: warning: unreachable code
           case n:Map[a,b]⇒println("Map[a,b]");n.size;
    

    其实这两行都是:

        case n:Map[a,b]⇒println("Map[a,b]");n.size;     
        case m:Map[_,_]⇒ m.size
    

    是不可达的,因为在 map 上匹配的所有三行都是等价的,至少它们的模式会匹配相同的东西。

    在运行时没有泛型类型,它们被删除,所以Map[A, B] 只是一个Map。所以你唯一匹配地图的案例是第一个,因为它们是按顺序测试的

    case n:Map[Int,Int]⇒println("Map[Int,Int]");var a =  n.iterator.next();println(a._1);println(a._2);n.size;      
    

    只有当您尝试使用将它们视为Int 的值时,您才会得到ClassCastException,因为只有当您尝试使用它们时它们才会被强制转换。检查size 不依赖于其值的类型。

    【讨论】:

      【解决方案2】:

      这个问题是由于泛型类型擦除而发生的。在运行时,任何类型的Map 之间没有区别。这就是为什么模式在第一个合适的情况下匹配的原因。

      简单的 sn-p 来检查它:

      List[String]().isInstanceOf[List[String]]    // true
      List[String]().isInstanceOf[List[Integer]]   // true
      

      【讨论】:

      • 我错过了。它确实回答了我的问题,感谢您的回复。
      【解决方案3】:

      这是因为类型擦除。泛型类型的使用在 case 子句中没有用,因为它不保留类型信息。所以MAP[String-&gt;Int] 等价于Map。这就是MAP[String-&gt;Int]MAP[Int-&gt;Int] 匹配的原因。

      【讨论】:

        【解决方案4】:

        如果不尝试使用模式匹配,而是使用隐式和类型类机制,会不会容易得多?

        trait TypePattern[A,B] {
          def pattern(a: A):B
        }
        
        implicit object stringPattern extends TypePattern[String,Int] {
          override def pattern(a: String): Int = a.length
        }
        
        implicit object mapIntIntPattern extends TypePattern[Map[Int, Int],Int] {
          override def pattern(n: Map[Int, Int]): Int = {
            println("Map[Int,Int]")
            var a =  n.iterator.next()
            println(a._1)
            println(a._2)
            n.size
          }
        }
        
        implicit object mapAnyPattern extends TypePattern[Map[Any, Any],Int] {
          override def pattern(a: Map[Any, Any]): Int = {
            println("Map[a,b]")
            a.size
          }
        }
        
        def pattern[A,B](x: A)(implicit typePattern: TypePattern[A,B]): B = {
          typePattern.pattern(x)
        }
        

        【讨论】:

          猜你喜欢
          • 2018-05-30
          • 1970-01-01
          • 1970-01-01
          • 2016-01-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多