Scala 2.10中的字符串插值 - 如何插入String变量?

Era*_*dan 46 scala string-interpolation scala-2.10

字符串插值在Scala启动Scala 2.10时可用

这是基本的例子

 val name = "World"            //> name  : String = World
 val message = s"Hello $name"  //> message  : String = Hello World
Run Code Online (Sandbox Code Playgroud)

我想知道是否有办法进行动态插值,例如以下(不编译,仅用于说明目的)

 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)
Run Code Online (Sandbox Code Playgroud)
  1. 有没有办法"动态"评估像这样的字符串?(或者它本身是错误的/不可能的)

  2. 究竟是s什么?它不是def方法(显然它是一个方法StringContext),而不是一个对象(如果它是,它会抛出一个不同于我认为未找到的编译错误)


Rex*_*err 36

s实际上是一个方法StringContext(或可以隐式转换的东西StringContext).当你写作

whatever"Here is text $identifier and more text"
Run Code Online (Sandbox Code Playgroud)

编译器将其贬低为

StringContext("Here is text ", " and more text").whatever(identifier)
Run Code Online (Sandbox Code Playgroud)

默认情况下,StringContext给你s,fraw*方法.

如您所见,编译器本身会选择名称并将其提供给方法.由于这是在编译时发生的,因此您无法动态地执行此操作 - 编译器在运行时没有关于变量名称的信息.

但是,您可以使用变量,因此您可以交换所需的值.默认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
Run Code Online (Sandbox Code Playgroud)

(在此示例中,REPL已调用0).

这是你能做的最好的事情.

*raw被打破,并且无法在2.10.1之前修复; 只有变量之前的文本才是实际原始的(没有转义处理).所以推迟使用那个,直到2.10.1出来,或者查看源代码并定义自己的代码.默认情况下,没有转义处理,因此定义自己的处理非常简单.

  • 一点小小的补充。不仅可以使用标识符。任何有效的 scala 表达式都可以放在 ${} 之间。 (2认同)

Era*_*dan 12

基于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
Run Code Online (Sandbox Code Playgroud)

  • 使用Scala 2.11.5,第二行给出错误"缺少参数类型名称".我认为它需要写成`val template =(name:Any)=> s"Hello $ name"`或`def template(name:Any)= s"Hello $ name"` (2认同)

Kip*_*ros 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 = {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)