[続き]Scala Macro Annotationによるコンフィギュレーション・アイテムのバインド
v0.1.2
前編に続き、@連城404の転送によりテキスト:
@連城404:おもしろくて、@conf val port=0の「=0」を外して現実的なタイプの説明に変える可能性はありますか?すなわち@conf port:Intという付与値はここでは全く実用的な意味がなく,制限を実現して導入されたノイズのようなものである.
確かに必要ありませんが、意味はあります:IDEは間違いを報告しません.(少なくとも私が使っているIDEA 14のscala pluginではScala Macroはサポートされていません)
答えはいいですが、@連城404に聞かれたとき、私はまだ方法を考えていませんでした.
解決方法は実は難しくなくて、前提は
調査:
具体的に実現するコードの提出は、0475d92cを参照する.
どのようにしてこれらの詳細を発見しますか?
v0.2.0
上の
作成が簡単であると同時に、クラス名定義が構成パスと厳密に一致するのは、すべてのシーンに適しているわけではありません.
例えば、
この場合、対応するクラス名が
命名に多くの時間を費やすよりも、より良い宣言方法を変えたほうがいい.
ええ、いいですね.問題を解決できます.ただ一周してまた帰ったような感じでした:
この二つの書き方に比べて、前者はあまり優位ではないようだ.
そのため、もう一つの書き方が誕生し、このAdding Reflection to Scala Macrosに啓発された.
その詳細については、
この新しい書き方には、コードからプロファイルを生成することが容易であり、エスケープのコストが小さいという利点がある.
うん...
前編に続き、@連城404の転送によりテキスト:
@連城404:おもしろくて、@conf val port=0の「=0」を外して現実的なタイプの説明に変える可能性はありますか?すなわち@conf port:Intという付与値はここでは全く実用的な意味がなく,制限を実現して導入されたノイズのようなものである.
class Server {
@conf val port = 0
// , :
// @conf val port: Int
}
確かに必要ありませんが、意味はあります:IDEは間違いを報告しません.(少なくとも私が使っているIDEA 14のscala pluginではScala Macroはサポートされていません)
= 0
は外してもいいですか?答えはいいですが、@連城404に聞かれたとき、私はまだ方法を考えていませんでした.
解決方法は実は難しくなくて、前提は
Scala AST
に対してよく知っていることです.調査:
case class ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree)
Modifiers
にはflags
の属性がある、ここではval port
の種々の特徴がマークする.val port: Int
とval port = 0
の違いはflags
から表れる.class ModifierFlags {
final val DEFERRED = 1 << 4 // was `abstract' for members | trait is virtual
final val DEFAULTINIT = 1L << 41 // symbol is initialized to the default value: used by -Xcheckinit
...
}
ModifierFlags
にはすべてのflags
の値が定義、ここでは2つの列挙が上記の2つの異なる書き方に対応することを抜粋する.具体的に実現するコードの提出は、0475d92cを参照する.
どのようにしてこれらの詳細を発見しますか?
print(x)
、未知のオブジェクトの表示情報を探査し、多くの場合重要な手がかりを提供することができる.print(x.getClass)
、上の方法は役に立たないので、そのタイプを明らかにして、それからソースコードをひっくり返す必要があります.v0.2.0
上の
v0.1.x
はValDef
に基づく声明スタイルで、実際に使用すると次のことがわかります.作成が簡単であると同時に、クラス名定義が構成パスと厳密に一致するのは、すべてのシーンに適しているわけではありません.
例えば、
Kafka
と書かれた消費クライアントは、アクセスサービスの構成項目を設計します.kafka_broker {
host = 10.0.0.1
port = 12306
}
この場合、対応するクラス名が
KafkaBroker
であることは明らかに設計意図に反し、KafkaConsumer
のように最も自然な選択である.命名に多くの時間を費やすよりも、より良い宣言方法を変えたほうがいい.
@conf
パラメータを使用して、デフォルトのコンフィギュレーション・アイテムのパスを変更できます.class KafkaConsumer {
@conf("kafka_broker.host") val host: String
}
ええ、いいですね.問題を解決できます.ただ一周してまた帰ったような感じでした:
class KafkaConsumer {
val host = conf.getString("kafka_broker.host")
}
この二つの書き方に比べて、前者はあまり優位ではないようだ.
Macro Annotation
によるコンフィギュレーション・アイテムのバインドを解決する目的は、コードのメタ情報とコンフィギュレーション・アイテムとのマッピング関係を確立し、中間文字列のHard Codeによる再構築に伴う追加コストを低減することである.そのため、もう一つの書き方が誕生し、このAdding Reflection to Scala Macrosに啓発された.
その詳細については、
v0.2.0
のREADMEを参照してください.この新しい書き方には、コードからプロファイルを生成することが容易であり、エスケープのコストが小さいという利点がある.
うん...
sbt plugin
と書きましょう.