2013-02-16 5 views
3

кажется, что TypeTags работают только для параметров типа, которые используются в параметрах вызываемого метода, а не тип возвращаемого значения:Почему TypeTag не работает для возвращаемых типов?

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

import scala.reflect.runtime.universe._ 

object Test { 
    def withParam[T: TypeTag](v: T): T = { 
    println(typeOf[T]) 
    0.asInstanceOf[T] 
    } 

    def justReturn[T: TypeTag](): T = { 
    println(typeOf[T]) 
    0.asInstanceOf[T] 
    } 
} 

// Exiting paste mode, now interpreting. 

import scala.reflect.runtime.universe._ 
defined module Test 


scala> val i: Int = Test.withParam(17) 
Int 
i: Int = 0 

scala> val j: Int = Test.justReturn() 
Nothing 
j: Int = 0 

Это согласуется с поведением манифеста в 2.9, но есть ли почему это невозможно сделать, и есть ли другой способ добиться этого эффекта?

+1

Что еще может это сделать? То есть, что _should_ 'justReturn' возвращается? –

ответ

2

Система типов начинается с наиболее ограничительного типа (т.е. Nothing, из которых не может быть экземпляров, если бы это было божественное значение, способное выдерживать что угодно и что-либо делать). Затем тип расширяется по мере необходимости, но поскольку возвращение находится в контравариантном положении, никогда не будет причины расширяться. Если вы действительно можете вернуть Nothing, вы должны быть установлены во всех ситуациях.

Затем вы подрываете систему типов, сообщая, что 0 является экземпляром Nothing. Конечно, это совершенно неверно, но компилятор покорно верит вам, и вы спасаете ситуацию, назначая ее Int, что и было на самом деле. (Он также с радостью попытается присвоить его String, и тогда вы получите исключение во время выполнения, потому что в этот момент это бессмысленно.)

Теоретически это можно сделать по-другому, но это довольно простая часть алгоритма вывода типа.

+1

Фактически, если вы вызываете исходный 'justReturn' с явным параметром типа, отличным от' Int', это ошибка времени компиляции. Интересно, что если вы даете явный параметр типа, совместимый с 'Int' через« слабое соответствие », ошибка возникает во время выполнения. Например, 'Test.justReturn [Byte]()' elicits 'java.lang.ClassCastException: java.lang.Integer нельзя отнести к java.lang.Byte'. –

+0

@RandallSchulz - Я получаю 'ClassCastExceptions' во всех случаях. Какую версию ты используешь? (2.10.0 здесь.) –

+0

Если так работает алгоритм, это имеет смысл. Благодарю. – Yan

2

Чтобы развернуть комментарий от Рекса Керра, нет ничего логичного вывода T в случае justReturn. Если Вы обеспечиваете (подходящий) тип параметра, вы получите это:

scala> val j: Int = Test.justReturn[Int]() 
Int 
j: Int = 0 

Если изменить justReturn к этому:

def justReturn[T: TypeTag]() { 
    println(typeOf[T]) 
} 

... то вы можете сделать это:

scala> justReturn[String]() 
String 

scala> justReturn[java.io.File]() 
java.io.File