2016-08-10 2 views
2

я был отчасти разочарован тем, что Scala компилятор позволяет компилировать это довольно странно, явно ошибочный код:Почему компилятор scala разрешает вызов PartialFunction без аргументов?

val foo: PartialFunction[Any, Unit] = { 
    case s: String => println(s) 
} 
foo() 

и вместо печати компиляции ошибок, оно проливает

Exception in thread "main" scala.MatchError:() (of class scala.runtime.BoxedUnit)

В чем причина этого?

ответ

4

В вашем случае ваша частичная функция принимает аргумент Any и включает в себя Unit (поскольку единица является подтипом Any - Any -> AnyVal -> Unit). Вызов apply(), который равен звоните apply(()).

Если у вас есть частичная функция, которая не принимать Unit вы получите сообщение об ошибке, указывающее, что аргумент применяется отсутствует:

scala> val foo : PartialFunction[AnyRef, Unit] = { 
    | case arg => println(s"arg = $arg") 
    | } 
foo: PartialFunction[AnyRef,Unit] = <function1> 

scala> foo() 
<console>:13: error: not enough arguments for method apply: (v1: AnyRef)Unit in trait Function1. 
Unspecified value parameter v1. 
     foo() 
1

Что послужило причиной для этого?

Поскольку при приеме параметра типа Any, компилятор делает вывод, что тип Unit применим в том случае, и, таким образом, передает Unit типа к foo.apply из PartialFunction:

def main(args: Array[String]): Unit = { 
    val foo: PartialFunction[Any,Unit] = ({ 
    @SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractPartialFunction[Any,Unit] with Serializable { 
     def <init>(): <$anon: Any => Unit> = { 
     $anonfun.super.<init>(); 
     () 
     }; 
     final override def applyOrElse[A1, B1 >: Unit](x1: A1, default: A1 => B1): B1 = ((x1.asInstanceOf[Any]: Any): Any @unchecked) match { 
     case (s @ (_: String)) => scala.this.Predef.println(s) 
     case (defaultCase$ @ _) => default.apply(x1) 
     }; 
     final def isDefinedAt(x1: Any): Boolean = ((x1.asInstanceOf[Any]: Any): Any @unchecked) match { 
     case (s @ (_: String)) => true 
     case (defaultCase$ @ _) => false 
     } 
    }; 
    new $anonfun() 
    }: PartialFunction[Any,Unit]); 
    foo.apply(()) 
} 

Если тип ограничение было более узким, то есть AnyRef, вы увидите ошибку компилятора, так как Unit наследует AnyVal, и теперь компилятор не может предоставить какую-либо скрытую «помощь».