简体   繁体   English

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

[英]How save a TypeTag and then use it later to reattach the type to an Any (Scala 2.10)

I am trying to make custom heterogeneous lists and maps. 我正在尝试制作自定义异构列表和地图。 Although there are examples around using Manifest, with Scala 2.10 they are deprecated and I should use TypeTags (or Classtags). 虽然有使用Manifest的例子,但是Scala 2.10它们已被弃用,我应该使用TypeTags(或Classtags)。 In the case of maps it seems I can preserve the binding of an Any to a Type using (say) a tuple String->(TypeTag[ _ <: Any ], Any ). 在地图的情况下,似乎我可以使用(比如)元组字符串 - >(TypeTag [_ <:Any],Any)保留Any与Type的绑定。

My problem is how to get from the recovered TypeTag and an undefined T, to be able to return an instance of TypeTag.tpe - at the point in the code where I have //** How do I use saved typeTag to define T here?** 我的问题是如何从恢复的TypeTag和未定义的T中获取,以便能够返回TypeTag.tpe的实例 - 在我所拥有的代码中的点//** How do I use saved typeTag to define T here?**

As written, there are no compiler errors in method get, but T is set to Nothing and returns Some(Nothing). 如上所述,方法get中没有编译器错误,但T设置为Nothing并返回Some(Nothing)。 I would like my commented-out line to work: case Some( x ) => // println( "Get 2*'pi'=" + x*2 ) where there is a complier message, "value * is not a member of Nothing". 我希望我的注释掉的行能够工作: case Some( x ) => // println( "Get 2*'pi'=" + x*2 )其中有一个编译器消息,“value *不是成员什么都没有”。 I realise I could write more compactly, but as done, I can mouse-over in my IDE and follow step by step. 我意识到我可以更紧凑地编写,但是完成后,我可以在我的IDE中鼠标悬停并按照一步一步进行操作。 There is a related question - Scala: What is a TypeTag and how do I use it? 有一个相关的问题 - Scala:什么是TypeTag以及如何使用它? but it does not seem to go the 'last mile' - retagging an Any. 但它似乎没有走“最后一英里” - 重新选择任何一个。

How to do this? 这个怎么做?

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

T is defined when you call the method get, you cant change it inside a function to another type. 当你调用方法get时定义了T,你不能在函数内部将其更改为另一种类型。 Compiler need information to get type information for T or you have to provide it explicitly: 编译器需要获取T的类型信息的信息,或者您必须明确提供它:

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

If a key is typed, then T can be inferred: 如果键入了键,则可以推断出T:

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

To check the type is correct when getting from map you can do what you did originally, save a type and a value: 从地图获取时检查类型是否正确您可以执行您最初执行的操作,保存类型和值:

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
}

Here is my own answer: 这是我自己的答案:

I don't need TypeTags and I don't really need a keyed type or a tuple. 我不需要TypeTags,我真的不需要键控类型或元组。 Just simple generics seems to do. 只是简单的泛型似乎做。 I don't need a match & case classes enumerating the possible values for Any. 我不需要枚举匹配和案例类来枚举Any的可能值。 Just a simple map of name-value pairs. 只是一个简单的名称 - 值对映射。 I then access it using 然后我使用它访问它

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

It seems reasonable and very readable to just invoke: hmap.get Float . 只需调用:hmap.get Float,这似乎是合理且可读的。 The types are not checked at compile time and so I will get runtime errors if I ask for the wrong type. 在编译时不检查类型,因此如果我要求错误的类型,我将得到运行时错误。 If I do decide to filter the types there is a place to do it. 如果我决定过滤类型,那么就有一个地方可以做到。 I should check for castability and let Option return None if it can't be done and not Exception as it does now. 我应该检查castable并让Option返回None,如果它不能完成,而不是现在的Exception。

To me the above is neater & reads nicer than casting later since all the error handling can be in the get rather than using : 对我来说,上面的内容比读后更好,因为所有的错误处理都可以在get中而不是使用:

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

Thanks for your help! 谢谢你的帮助!

Here is the simpler code now: 这是现在更简单的代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM