如何保存TypeTag,然后再使用它将类型重新附加到Any(Scala 2.10)

时间:2012-10-31 18:40:03

标签: scala scala-2.10

我正在尝试制作自定义异构列表和地图。虽然有使用Manifest的例子,但是Scala 2.10它们已被弃用,我应该使用TypeTags(或Classtags)。在地图的情况下,似乎我可以使用(比如)元组String->(TypeTag [_&lt ;: Any],Any)来保留Any与Type的绑定。

我的问题是如何从恢复的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 )其中有一个编译器消息,“value *不是Nothing的成员”。 我意识到我可以更紧凑地编写,但是完成后,我可以在我的IDE中鼠标悬停并按照一步一步进行操作。有一个相关的问题 - Scala: What is a TypeTag and how do I use it?但它似乎没有走“最后一英里” - 重新推出任何一个。

怎么做?

这是我到目前为止的代码:

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
  }
}

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 } }

2 个答案:

答案 0 :(得分:0)

当你调用方法get时定义了T,你不能在函数内部将其更改为另一种类型。编译器需要获取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
}

答案 1 :(得分:0)

以下是我自己的回答:

我不需要TypeTags而且我不需要键控类型或元组。只是简单的泛型似乎做。我不需要比赛&amp; case类枚举Any的可能值。只是一个简单的名称 - 值对映射。然后我使用它访问它

hmap.get Float .... println( "Get 'pi'=" + x * 2 )

调用它似乎合理且非常易读:hmap.get Float。在编译时不检查类型,因此如果我要求错误的类型,我将得到运行时错误。如果我决定过滤类型,那么就有一个地方可以做到。我应该检查可转换性并让Option返回None,如果它不能完成,而不是现在的Exception。

对我来说上面的内容更整洁了。因为所有的错误处理都可以在get中而不是使用:  

hmap.get("pi").asInstanceOf[Float].

感谢您的帮助!

现在是更简单的代码:

 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[ Float]( "pi" )
    result match {
      case Some( x ) =>
        println( "Get 'pi'=" + x * 2 )
      case _ => println("Not found")
    }
  }
}

class HMap {
  private var coreMap =
    Map.empty[ String, Any ]

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

  def get[ T ]( key: String ): Option[ T ] = {
    val option = coreMap.get( key )
    option match {
      case None      => None
      case Some( x ) => Some( x.asInstanceOf[ T ] )
    }
  }
}

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[ Float]( "pi" ) result match { case Some( x ) => println( "Get 'pi'=" + x * 2 ) case _ => println("Not found") } } } class HMap { private var coreMap = Map.empty[ String, Any ] // Save the key with the value def update[ T ]( key: String, value: T ) = coreMap.put( key, value ) def get[ T ]( key: String ): Option[ T ] = { val option = coreMap.get( key ) option match { case None => None case Some( x ) => Some( x.asInstanceOf[ T ] ) } } }