web-dev-qa-db-ja.com

Scala 2.10-文字列変数を補間する方法は?

文字列補間は Scalaで利用可能 開始Scala 2.10

これは基本的な例です

 val name = "World"            //> name  : String = World
 val message = s"Hello $name"  //> message  : String = Hello World

動的補間を行う方法があるかどうか疑問に思っていました。以下(説明のためにコンパイルされていません)

 val name = "World"            //> name  : String = World
 val template = "Hello $name"  //> template  : String = Hello $name
 //just for illustration:
 val message = s(template)     //> doesn't compile (not found: value s)
  1. そのような文字列を「動的に」評価する方法はありますか? (またはそれは本質的に間違っている/不可能です)

  2. そして、sとは正確には何ですか? それはメソッドの定義ではありませんどうやらそれはStringContext のメソッドです)、オブジェクトではありません(そうであった場合、とは異なるコンパイルエラーをスローします見つかった私は思う)


46
Eran Medan

sは、実際にはStringContext(またはStringContextから暗黙的に変換できるもの)のメソッドです。あなたが書くとき

whatever"Here is text $identifier and more text"

コンパイラはそれをdesugars

StringContext("Here is text ", " and more text").whatever(identifier)

デフォルトでは、StringContextsf、およびraw *メソッドを提供します。

ご覧のとおり、コンパイラ自体が名前を取り出してメソッドに渡します。これはコンパイル時に発生するため、動的に行うことはできません。コンパイラには実行時の変数名に関する情報がありません。

ただし、varsを使用できるため、必要な値を入れ替えることができます。そして、デフォルトのsメソッドは、(予想通り)toStringを呼び出すだけなので、次のようなゲームをプレイできます。

class PrintCounter {
  var i = 0
  override def toString = { val ans = i.toString; i += 1; ans }
}

val pc = new PrintCounter
def pr[A](a: A) { println(s"$pc: $a") }
scala> List("salmon","herring").foreach(pr)
1: salmon
2: herring

(0はすでにREPL)によって呼び出されました)。

それはあなたができる最高のことです。

*rawは壊れており、2.10.1まで修正される予定はありません。変数の前のテキストのみが実際に生です(エスケープ処理はありません)。そのため、2.10.1がリリースされるまで、その使用を控えるか、ソースコードを確認して独自のコードを定義してください。デフォルトでは、エスケープ処理がないため、独自の定義は非常に簡単です。

36
Rex Kerr

レックスの優れた回答に基づく元の質問のコンテキストで、#1の可能な解決策を次に示します

val name = "World"                  //> name: String = World
val template = name=>s"Hello $name" //> template: Seq[Any]=>String = <function1>
val message = template(name)        //> message: String = Hello World
12
Eran Medan
  1. 文字列補間はコンパイル時に行われるため、コンパイラーは通常、s(str)を補間するのに十分な情報を持っていません。文字列リテラル SIPによると が必要です。
  2. リンクしたドキュメントのAdvanced Usageで、_id"Hello $name ."_形式の式がコンパイル時にnew StringContext("Hello", "."). id(name)

idは、暗黙のクラスを通じて導入されたユーザー定義の補間関数である可能性があることに注意してください。ドキュメントはjson補間器の例を示しています、

_implicit class JsonHelper(val sc: StringContext) extends AnyVal {
  def json(args: Any*): JSONObject = {
    ...
  }
}
_
7
Kipton Barros

これは、現在の実装では本質的に不可能です。ローカル変数名は実行時に利用できません。デバッグシンボルとして保持されている可能性がありますが、削除されている場合もあります。 (メンバー変数名はそうですが、ここでは説明していません)。

1
jsalvata