2012-11-11 8 views
6

私はREST Webサービスへのラッパーを作成しています。強く型付けされたScala APIを使用したいと思います。Scalaの名前付きパラメータの名前と値を持つMap [String、Any]を持つことは可能ですか?

次は私がこれまでやっているものです:

def getMentions(count: Option[Int] = None, 
       sinceID: Option[TweetID] = None, 
       maxID: Option[TweetID] = None, 
       trimUser: Option[Boolean] = None, 
       contributorDetails: Option[Boolean] = None, 
       includeEntities: Option[Boolean] = None) : List[Tweet] = { 
val parameters = Map("count" -> count, 
        "since_id" -> sinceID, 
        "max_id" -> maxID, 
        "trim_user" -> trimUser, 
        "contributor_details" -> contributorDetails, 
        "include_entities" -> includeEntities) 
/* 
* Convert parameters, which is a Map[String,Any] to a Map[String,String] 
* (Removing Nones) and pass it to an object in charge of generating the request. 
*/ 
... 
} 

このアプローチ働いたが、それは手動でparametersマップを生成するために私を必要としています。 パラメータとその値を表すマップにアクセスできたなら、私がやっていることははるかにクリーンになります。

答えて

11

ランタイムリフレクションでこれを行うことができます。希望する場合はどうすればいいのかを知ることができますが、これは実際にはScala 2.10's macrosのきちんとした使用例です。私は読者のために(簡単に)運動としてマップキーケースヘビを残しておきます

object ParamMapMaker { 
    def paramMap: Map[String, Any] = macro paramMapImpl 

    def paramMapImpl(c: scala.reflect.macros.Context) = { 
    import c.universe._ 

    val params = c.enclosingMethod match { 
     case DefDef(_, _, _, ps :: Nil, _, _) => 
     ps.map(p => 
      reify((
      c.Expr[String](Literal(Constant(p.name.decoded))).splice, 
      c.Expr[Any](Ident(p.symbol)).splice 
     )).tree 
     ) 
     case _ => c.abort(c.enclosingPosition, "Can't call paramMap here!") 
    } 

    c.Expr[Map[String, Any]](Apply(Select(Ident("Map"), "apply"), params)) 
    } 
} 

:まず、我々はParamMapMaker.scalaという名前のファイルがあるとします。

我々はまた、(Test.scalaという名前の)テストファイルがあります。

object Test extends App { 
    def foo(hello: String, answer: Int) = ParamMapMaker.paramMap 

    println(foo("world", 42)) 
} 

今、私たちはこれらの両方をコンパイルします。

scalac -language:experimental.macros ParamMapMaker.scala 
scalac Test.scala 

を我々はTestを実行したとき、我々は次のことを得られます。

Map(hello -> world, answer -> 42) 

これについての気難しいことは、rのオーバーヘッドがないことですアンティメ我々は-Ymacro-debug-verboseでテストファイルをコンパイルする場合、私たちは、次のコードはコンパイル時にfooの体のために(実質的に)生成されていることを参照してください。

Map.apply[String, Any](
    scala.Tuple2.apply[String, String]("hello", hello), 
    scala.Tuple2.apply[String, Int]("answer", answer) 
) 

まさに我々が期待通り。

+1

sbtで使用できるかどうか知っていますか? – mariosangiorgio

+3

私はそれを理解しました。 scalaバージョンのscalaVersion:= "2.10.0-RC2"を変更し、フィーチャーを使用してファイルに ' import language.experimental.macros'をインポートするだけです – mariosangiorgio

関連する問題