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)

默认情况下,StringContext为您提供sfraw* 方法。

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

但是,您可以使用 var,因此您可以交换所需的值。并且默认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

(在此示例中,REPL 已经调用了 0)。

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

*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 回答