49

文字列補間は Scala 2.10 以降の Scala で使用できます。

これは基本的な例です

 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あり、オブジェクトではありません (もしそうなら、見つからないよりも別のコンパイル エラーをスローしたと思います)。


4

4 に答える 4

38

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

whatever"Here is text $identifier and more text"

コンパイラはそれを脱糖します

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

デフォルトでStringContexts、 、f、および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 がリリースされるまでその使用を保留するか、ソース コードを見て独自のコードを定義してください。デフォルトではエスケープ処理はありませんので、独自に定義するのは非常に簡単です。

于 2012-11-07T00:01:26.730 に答える
14

Rexの優れた回答に基づく元の質問のコンテキストでの#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
于 2012-11-07T01:29:18.823 に答える
7
  1. 文字列の補間はコンパイル時に行われるため、コンパイラには通常、補間するのに十分な情報がありませんs(str)SIP によると、文字列リテラルが必要です。
  2. リンクしたドキュメントの高度な使用法の下で、フォームの式がid"Hello $name ."コンパイル時に に変換されることが説明されていnew StringContext("Hello", "."). id(name)ます。

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

implicit class JsonHelper(val sc: StringContext) extends AnyVal {
  def json(args: Any*): JSONObject = {
    ...
  }
}
于 2012-11-06T23:54:42.383 に答える
1

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

于 2012-11-07T00:17:25.483 に答える