質問

The code below checks for basic auth. Here resp is the 401 unauthorized response. I check if an Authorization header is present and if present I verify its value otherwise I call resp:

def validate(authHeader: String): Boolean = {
   //........
} 
val authHeader = Option(request.getHeader("Authorization"))
authHeader match {
  case Some(header) if header.startsWith("Basic ") => validate(header) match { case false => resp }
  case _ => resp
}

When I compile it, it gives error for line match { case false => resp } saying found: scala.Boolean(false) required: java.lang.Boolean. I am confused about why its treating scala Boolean different from java Boolean.

I noticed there was a line import java.lang._ at the beginning of the file (I don't know why). I commented it out and the code give a warning instead of an error:

warning: match may not be exhaustive.
It would fail on the following input: true

I think this is because I didn't write the case true. But what made the original error happen, and why does it only happen with import java.lang._?

EDIT:

Here is a minimal example for the problem:

val f: java.lang.Boolean = false
val f2: scala.Boolean = false

/* The following line produces this error:
error: type mismatch;
 found   : scala.Boolean(false)
 required: java.lang.Boolean
*/
f match { case false => 5 }

/* The following line produces this warning:
warning: match may not be exhaustive.
It would fail on the following input: true
*/
f2 match { case false => 5 }
役に立ちましたか?

解決

It seems that implicit conversions are not in effect in the case of pattern matching.

Consider:

scala> case class Foo(x: Int)
defined class Foo

scala> case class Bar(x: Int)
defined class Bar

scala> implicit def foo2bar(x: Foo) = Bar(x.x)
foo2bar: (x: Foo)Bar

scala> Foo(3) match { case Foo(3) => 3; case _ => 4 }
res19: Int = 3

scala> Foo(3) match { case Bar(3) => 3; case _ => 4 }
<console>:14: error: constructor cannot be instantiated to expected type;
 found   : Bar
 required: Foo
              Foo(3) match { case Bar(3) => 3; case _ => 4 }
                                  ^

Compare with:

scala> val f: java.lang.Boolean = false
f: Boolean = false

scala> f.<TAB>
asInstanceOf   booleanValue   compareTo      isInstanceOf   toString       

scala> f || true
res21: Boolean = true

implicit conversions worked here, but not here:

scala> f match { case false => 3; case true => 4 }
<console>:15: error: type mismatch;
 found   : scala.Boolean(false)
 required: java.lang.Boolean
              f match { case false => 3; case true => 4 }
                             ^
<console>:15: error: type mismatch;
 found   : scala.Boolean(true)
 required: java.lang.Boolean
              f match { case false => 3; case true => 4 }
                                              ^

I agree that this is quite counterintuitive but I doubt it could be fixed without introducing a special casing to the language, or making scalac somehow recognize pattern matches where all patterns belong to a single type, and try to find an implicit conversion to that type. The workaround would be to do an explicit asInstanceOf[Boolean] cast. Although it's odd that the following works fine:

scala> "foobar".startsWith("foo") match { case true => 3 ; case false => 4 }
res26: Int = 3
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top