Как сохранить TypeTag, а затем использовать его позже, чтобы повторно прикрепить тип к Any (Scala 2.10)

Я пытаюсь создать собственные разнородные списки и карты. Хотя есть примеры использования Manifest, в Scala 2.10 они устарели, и я должен использовать TypeTags (или Classtags). В случае с картами кажется, что я могу сохранить привязку Any к Type, используя (скажем) кортеж String->(TypeTag[ _ ‹: Any ], Any ).

Моя проблема заключается в том, как получить из восстановленного TypeTag и неопределенного T, чтобы иметь возможность вернуть экземпляр TypeTag.tpe - в той точке кода, где у меня есть //** How do I use saved typeTag to define T here?**

Как написано, в методе get нет ошибок компилятора, но T имеет значение Nothing и возвращает Some(Nothing). Я хотел бы, чтобы моя закомментированная строка работала: case Some( x ) => // println( "Get 2*'pi'=" + x*2 ), где есть сообщение компилятора, «значение * не является членом Nothing». Я понимаю, что мог бы написать более компактно, но когда это сделано, я могу навести указатель мыши в своей IDE и следовать шаг за шагом. Есть связанный с этим вопрос - Scala: что такое TypeTag и как его использовать? но, похоже, он не проходит «последнюю милю» — перемаркировку Any.

Как это сделать?

Here is the code I have so far:

import scala.reflect._
import scala.reflect.runtime.universe._
import collection.mutable.Map

object Test extends HMap {

  def main( args: Array[ String ] ) {

    var hmap = new HMap
    hmap( "anInt" ) = 1
    hmap( "pi" ) = 3.1416f
    hmap( "c" ) = "hello"
    // Test
    val result = hmap.get( "pi" )
    result match {
      case Some( x ) =>
        println( "Get 'pi'=" + x*2 )
      case _ =>
    }
  }
}

class HMap {
  private var coreMap = 
    Map.empty[ String, ( TypeTag[ _ <: Any ], Any ) ]

  // Save the type tag with the value
  def update[ T: TypeTag ]( key: String, value: T ) = 
    coreMap.put( key, ( typeTag[ T ], value ) )

  override def toString = coreMap.toString

  def get[ T: TypeTag ]( key: String ): Option[ T ] = {
    val option = coreMap.get( key )
    val result = option match {
      case None => None
      case Some( x ) => {
        val typeTag = x._1; val value = x._2
        println( "Matched Type = " + 
            typeTag.tpe + "   Value=" + value )
        // **** How do I use saved typeTag to define T here? ****
        val v = value.asInstanceOf[ T ]
        val s = Some( v )
        println( "Returning " + s )
        s
      }
    }
    result
  }
}


person Magpie    schedule 31.10.2012    source источник
comment
Я хотел бы упомянуть, что мы отменили наше решение отказаться от Manifest. В RC1 устарел только ClassManifest, но не Manifest.   -  person Eugene Burmako    schedule 31.10.2012
comment
Также не могли бы вы дать ссылку на примеры использования манифестов? Я не уверен, что возможно реализовать get с предоставленной подписью, которая будет работать так, как вы хотите, даже с манифестами.   -  person Eugene Burmako    schedule 31.10.2012
comment
@Eugene Burmako: будут ли манифесты объявлены устаревшими в более позднем выпуске или вообще не будут?   -  person Arjan    schedule 31.10.2012
comment
Вот пример использования типизированного ключа: codeslashslashcomment.com/2012/03/11/, как предложено @Arjan ниже.   -  person Magpie    schedule 01.11.2012
comment
Мне не нравится указывать тип снова, так как это часть информации, которую я пытаюсь найти. Что, если я использую две карты, обе с использованием одного и того же ключа, одна с TypeTag, а другая со значениями (или перестановкой той же идеи), то, когда я сделаю второй get, у меня уже будет typeTag без того, чтобы исходный вызывающий объект имел пришлось указать еще раз. Таким образом, возникает вопрос, как получить typeTag в T из get? получить [aTypeTag.tpe] (пи). Или, в качестве альтернативы, создать некоторый экземпляр aTypeTag и использовать его в качестве второго аргумента и вывести из него тип для второго получения ??   -  person Magpie    schedule 01.11.2012
comment
@Arjan Мы хотели бы немедленно отказаться от манифестов, но их замена, TypeTags, зависит от отражения, которое стало экспериментальным с выпуском RC1 (первоначально мы думали, что сможем привести отражение в хорошую форму к финальному выпуску, но когда пришло время релиза мы поняли что еще не совсем там). В одном из последующих выпусков (надеюсь, в одном из выпусков 2.10.x), когда отражение станет неэкспериментальным, манифесты станут устаревшими.   -  person Eugene Burmako    schedule 01.11.2012
comment
@Eugene Burmako: спасибо за информацию   -  person Arjan    schedule 01.11.2012


Ответы (2)


T определяется, когда вы вызываете метод get, вы не можете изменить его внутри функции на другой тип. Компилятору нужна информация, чтобы получить информацию о типе для T, или вы должны предоставить ее явно:

def get[T](key: String) = m.get(key).map(_.asInstanceOf[T])
get[Int]("anInt")

Если ключ введен, то T может быть выведен:

class Key[T](name: String)
def get[T](key: Key[T]) = ...
get(Key[Int]("anInt"))

Чтобы проверить правильность типа при получении с карты, вы можете сделать то же, что и изначально, сохранить тип и значение:

val m = Map.empty[String, (Type, Any)]

def put[T: TypeTag](key: String, value: T) = m.put(key, (typeOf[T], value))

def get[T: TypeTag](key: String) = m.get(key) match {
    case Some((t, v)) if t =:= typeOf[T] => Some(v.asInstanceOf[T])
    case _ => None
}
person Arjan    schedule 31.10.2012

person    schedule
comment
чем это отличается от моего 1. решения? - person Arjan; 01.11.2012
comment
@Arjan Мои извинения - я был сосредоточен на вашем решении 2. - person Magpie; 01.11.2012
comment
Арьян и @Eugene Burmako: Я продолжил свой пример, чтобы исключить возможность исключения, если указан неправильный тип, скажем, get[Int]Pi, когда это должно было быть get[Float]Pi. Мне нужно проверить, что объект x, который я получаю с карты, является T. Я использую def get[T:TypeTag](key:String), так что теперь я получаю предупреждения компилятора. Если я скажу case Some(x:T), я получу шаблон абстрактного типа T, который не проверяется, поскольку он удаляется путем стирания. Если я попробую x.instanceOf[T], я получу абстрактный тип T, который не проверяется, поскольку он удаляется путем стирания. Как проверить, что x является T? - person Magpie; 01.11.2012