5

カスタムの異種リストとマップを作成しようとしています。マニフェストの使用に関する例はありますが、Scala 2.10では非推奨であり、TypeTags(またはClasstags)を使用する必要があります。マップの場合、(たとえば)タプルString->(TypeTag [_ <: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 )ます。「値*はNothingのメンバーではありません」というメッセージが表示されます。もっとコンパクトに書くことができると思いますが、そうすることで、IDEにマウスオーバーして、ステップバイステップで進むことができます。関連する質問があります-Scala:TypeTagとは何ですか?どのように使用しますか? しかし、それは「ラストマイル」にはならないようです-Anyのタグを付け直します。

これを行う方法?

これが私がこれまでに持っているコードです:

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

4

2 に答える 2

1

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
}
于 2012-10-31T19:48:15.760 に答える
0

これが私自身の答えです:

TypeTags は必要ありませんし、キー付きの型やタプルも必要ありません。単純なジェネリックだけがそうです。Any の可能な値を列挙する match & case クラスは必要ありません。名前と値のペアの単純なマップ。次に、次を使用してアクセスします

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

hmap.get Float を呼び出すだけでも合理的で非常に読みやすいようです。型はコンパイル時にチェックされないため、間違った型を要求すると実行時エラーが発生します。タイプをフィルタリングすることにした場合は、それを行う場所があります。キャスタビリティをチェックし、実行できない場合は Option が None を返すようにし、現在のように Exception を返さないようにする必要があります。

私にとって、上記は、後でキャストするよりもきれいで読みやすいです。

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

于 2012-11-01T04:51:57.190 に答える