简体   繁体   中英

Confusing type mismatch in Scala

I have:

val words = List("all", "the", "words", "all", "the", "counts", "all", "day")
val map = Exercise02.count(words.iterator)
val expected = Map("all" -> 3, "the" -> 2, "words" -> 1, "counts" -> 1, "day" -> 1)

where Exercise02.count is java.util.Iterator[String] => Map[String, Int] and merely produces a count of each word in the input java.util.Iterator[String] .

I wrote a test:

object Exercise02Spec extends FlatSpec with Inspectors {
  val words = List("all", "the", "words", "all", "the", "counts", "all", "day")
  val map = Exercise02.count(words.iterator)
  val expected = Map("all" -> 3, "the" -> 2, "words" -> 1, "counts" -> 1, "day" -> 1)

  "count" should "count the occurrence of each word" in {
    forAll (map) { kv => assert(kv._2 === expected(kv._1)) }
    // forAll (map) { (k: String, v: Int) => assert(v === expected(k)) }
  }
}

The first line compiles just fine, and the test passes. If I replace the first line with the commented out second line, I get a compilation error.

  • sbt reports: found : (String, Int) => Unit, required: ((String, Int)) => Unit
  • IntelliJ IDEA reports: Type mismatch, expected: ((String, Int)) => Unit, actual: (String, Int) => Unit

Why is this? And how do I fix it?

The method you're using accepts a function that transforms a single argument to a single output. What you're telling Scala in your second statement is that map should accept a function with two arguments! There's an important difference between a single argument that just happens to be a tuple of size two, and two distinct arguments.

So you have single argument, but you (and Scala) know it's a tuple. To access those two elements, you have to destructure or pattern match your argument against the tuple you want. You just do that by writing forAll (map) { case (k: String, v: Int) => assert(v === expected(k)) } . You're saying the argument you receive should match the pattern of a tuple (String, Int) and you want the first element bound to k and the second to v . You could probably eliminate mentioning the types explicitly here. Note that this is similar to the syntax used in pattern matching, which is essentially what you're doing here.

In the 2nd example you're defining a two argument function, not a single tuple argument function. Hence why the error is saying it is expecting the double parenthesis around the argument.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM