2016-10-24 2 views
3

У меня есть следующий код, чтобы бросить значение к типу умолчанию:Scala приведен к типу переменной

def fct[T](value: Any, default: T): T = { 
    val result = value.asInstanceOf[T] 
    println(result, result.getClass.getName, result.isInstanceOf[T]) 
    result 
} 

val res = fct("foo", 42) 

Какой результат является:

(foo,java.lang.String,true) 
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
    at scala.runtime.BoxesRunTime.unboxToInt(Test.sc2.tmp) 
    at #worksheet#.res$lzycompute(Test.sc2.tmp:7) 
    at #worksheet#.res(Test.sc2.tmp:7) 
    at #worksheet#.#worksheet#(Test.sc2.tmp:7) 

Вопрос: почему println отображается? Бросок должен потерпеть неудачу. Я попытался попробовать/поймать 3 строки, но во время вызова функции не возникает никаких исключений.

+1

Это странно. Обратите внимание, что я получаю результат '(Some (foo), scala.Some, true)' из вашего кода. – Yawar

+0

Да, извините, я исправлю это – Benjamin

+0

Это странно. И я получаю '(foo, java.lang.String, true)' на консоли Scala 2.11.8. Тело функции как-то лениво выполнено. Что странно. –

ответ

7

Из-за типа стирания, это невозможно фактически реализации value.{as/is}InstanceOf[T] где T является параметром типа. Дизайнеры Scala решили, что все еще должны компилироваться, но value.asInstanceOf[T] на самом деле не-op (как и эквивалент (T) value в Java), а value.isInstanceOf[T] всегда возвращает true (в Java, value instanceOf T - ошибка компилятора). (Так как он никогда не делает то, что вы хотите, я бы сильно хотел бы видеть предупреждение вместо этого, по крайней мере, для isInstanceOf.)

Но Scala позволяет делать то, что вы хотите с помощью ClassTag:

import scala.reflect.ClassTag 

def fct[T](value: Any, default: T)(implicit tag: ClassTag[T]): T = { 
    val result = (tag match { 
     case ClassTag.Int => value.asInstanceOf[Int] 
     ... same for other primitives 
     case _ => tag.runtimeClass.cast(value) 
    }).asInstanceOf[T] 
    println(result, result.getClass.getName, tag.runtimeClass.isInstance(result)) 
    result 
} 

(Вы еще нужно asInstanceOf[T] потому tag.runtimeClassобычно возвращает тот же класс T представляет, но не всегда, поэтому ее статический тип возврата должен быть Class[_] и cast возвращается Any).

Однако соответствия шаблон : T обрабатывает наличие ClassTag автоматически и уже обрабатывает бокс, так

def fct[T](value: Any, default: T)(implicit tag: ClassTag[T]): T = value match { 
    case result: T => result 
    case _ => default // or whatever you want to do if value is not a T 
} 

это лучший способ сделать это.

+2

Это называется просветлением. –

+2

Черт, я хочу быть тебе, когда я вырасту – Yawar

+0

Не компилируется: Ошибка: (6, 4) несоответствие типа; найдено: result.type (с базовым типом Любой) : T результат ^ – Benjamin

Смежные вопросы