0

我有一个脚本。它在没有警告的情况下运行。

$ cat ~/tmp/so1.scala 
import org.yaml.snakeyaml.Yaml

class JavaMapIteratorWrapper[K,V] (map: java.util.Map[K,V]) {
  def foreach (f: Tuple2 [K, V] => Unit): Unit = {
    val iter = map.entrySet.iterator
    while (iter.hasNext) {
      val entry = iter.next
      f (entry.getKey, entry.getValue)
    }
  }
}

implicit def foreachJavaMap[K,V] (map: java.util.Map[K,V]): JavaMapIteratorWrapper[K,V] = new JavaMapIteratorWrapper[K,V](map)

val yaml = new Yaml;
(yaml load (io.Source.fromFile(argv(0)).mkString)) match {
  case map: java.util.Map [_, _] => {
    for (entry <- map) {
      entry match {
        case ("id", id: String) => System.out.println ("ID is " + id)
        case (n: String, v: String) => System.out.println (n + " = " + v)
      }
    }
  }
}

$ scala -unchecked -classpath jar/snakeyaml-1.7.jar ~/tmp/so1.scala eg/default.yaml
(program output as expected)

我想将循环提取到它自己的函数中。所以我试试。

$ cat ~/tmp/so2.scala 
import org.yaml.snakeyaml.Yaml

class JavaMapIteratorWrapper[K,V] (map: java.util.Map[K,V]) {
  def foreach (f: Tuple2 [K, V] => Unit): Unit = {
    val iter = map.entrySet.iterator
    while (iter.hasNext) {
      val entry = iter.next
      f (entry.getKey, entry.getValue)
    }
  }
}

implicit def foreachJavaMap[K,V] (map: java.util.Map[K,V]): JavaMapIteratorWrapper[K,V] = new JavaMapIteratorWrapper[K,V](map)

val processMap = (map: java.util.Map [_, _]) => {
  for (entry <- map) {      // line 16
    entry match {
      case ("id", id: String) => System.out.println ("ID is " + id)
      case (n: String, v: String) => System.out.println (n + " = " + v)
    }
  }
}

val yaml = new Yaml;
(yaml load (io.Source.fromFile(argv(0)).mkString)) match {
  case map: java.util.Map [_, _] => processMap (map)
}

$ scala -unchecked -classpath jar/snakeyaml-1.7.jar ~/tmp/so2.scala eg/default.yaml
(fragment of so2.scala):16: error: type mismatch;
 found   : map.type (with underlying type java.util.Map[_, _])
 required: java.util.Map[_$1,_$2] where type _$2, type _$1
  for (entry <- map) {
                 ^
one error found
!!!
discarding <script preamble>

循环在它自己的函数中意味着它需要更具体的类型。好的。

我会尝试使用java.util.Map [AnyRef, AnyRef]而不是java.util.Map [_, _].

$ cat ~/tmp/so3.scala 
import org.yaml.snakeyaml.Yaml

class JavaMapIteratorWrapper[K,V] (map: java.util.Map[K,V]) {
  def foreach (f: Tuple2 [K, V] => Unit): Unit = {
    val iter = map.entrySet.iterator
    while (iter.hasNext) {
      val entry = iter.next
      f (entry.getKey, entry.getValue)
    }
  }
}

implicit def foreachJavaMap[K,V] (map: java.util.Map[K,V]): JavaMapIteratorWrapper[K,V] = new JavaMapIteratorWrapper[K,V](map)

val processMap = (map: java.util.Map [AnyRef, AnyRef]) => {
  for (entry <- map) {
    entry match {
      case ("id", id: String) => System.out.println ("ID is " + id)
      case (n: String, v: String) => System.out.println (n + " = " + v)
    }
  }
}

val yaml = new Yaml;
(yaml load (io.Source.fromFile(argv(0)).mkString)) match {
  case map: java.util.Map [AnyRef, AnyRef] => processMap (map)      // line 26
}

$ scala -unchecked -classpath jar/snakeyaml-1.7.jar ~/tmp/so3.scala eg/default.yaml
(fragment of so3.scala):26: warning: non variable type-argument AnyRef in type pattern is unchecked since it is eliminated by erasure
  case map: java.util.Map [AnyRef, AnyRef] => processMap (map)
                       ^
one warning found
!!!
discarding <script preamble>
(program output as expected)

所以现在它运行了,但它给了我一个警告。如何消除该警告?

笔记:

  1. org.yaml.snakeyaml.Yaml 是用 Java 编写的,所以我不能使用类型清单。(我可以吗?)
  2. 我的真实程序使用了几个 Java 库,所以当我对给出的类型做出可能的错误假设时,我希望得到警告。但是我如何告诉编译器“是的,我已经检查过了,它是正确的,不要再警告我了”?
  3. 我正在使用 scala 2.7.7(因为这是与 Ubuntu 一起打包的版本)。
4

2 回答 2

3

您可以尝试删除自定义包装器。(2.8.1) Scala 标准库已经包含一个包装器,可以更惯用地使用 Java 集合类型,在scala.collection.JavaConverters. (注意:scala.导入时不需要前缀)

我还会创建processMap一个方法而不是函数,并添加类型参数:

import collection.JavaConverters._

def processMap[K,V](map: Map[K, V]): Unit = {
  for (entry <- map) {
    entry match {
      case ("id", id: String) => System.out.println ("ID is " + id)
      case (n: String, v: String) => System.out.println (n + " = " + v)
    }
  }
}

val yaml = new Yaml
(yaml load (io.Source.fromFile(argv(0)).mkString)) match {
  case map: java.util.Map[_, _] => processMap(map.asScala)
}

注意asScala倒数第二行的方法...

在处理 Java/Scala 互操作时,通常最好的做法是尽早从 Java 转换为 Scala 集合,并尽可能晚地转换回来。

于 2011-03-12T18:13:24.637 回答
0

您必须使用 Scala 2.7.X。如果您使用 2.8.1,则您的 Map[_,_] 示例可以正常工作。

如果您需要使用 2.7.X,请尝试将您的 processMap 值转换为方法: def processMap[K,V] = (map: java.util.Map[K,V]) => {...} 这似乎为我编译,但请注意我使用 YAML 库“存根”了这些部分。我用了:

val m1 = new java.util.HashMap[String,String]
m1.put("one", "1")
m1.put("id", "123")
m1.put("two", "2")

m1 match {
  case map: java.util.Map [_, _] => processMap (map)
}
于 2011-03-12T18:02:59.323 回答