字符串插值是available in 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)
有没有办法动态"动态"像那样评估一个字符串? (或者它本身就是错误/不可能)
究竟是什么s
? 它不是一个方法def (apparently it is a method on StringContext
),而不是一个对象(如果是,它会抛出一个不同于找不到的编译错误我认为)
答案 0 :(得分:33)
s
实际上是StringContext
上的一种方法(或者可以从StringContext
隐式转换的方法)。当你写
whatever"Here is text $identifier and more text"
编译器将其篡改为
StringContext("Here is text ", " and more text").whatever(identifier)
默认情况下,StringContext
会为您提供s
,f
和raw
*方法。
正如您所看到的,编译器本身会选择名称并将其提供给方法。由于这是在编译时发生的,因此您无法动态地执行此操作 - 编译器在运行时没有关于变量名的信息。
但是,您可以使用变量,因此您可以交换所需的值。默认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出来,或者查看源代码并定义自己的代码。默认情况下,没有转义处理,因此定义自己的转义非常简单。
答案 1 :(得分:11)
根据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
答案 2 :(得分:7)
s(str)
。它需要一个字符串文字,according to the SIP。id"Hello $name ."
形式的表达式在编译时被翻译为new StringContext("Hello", "."). id(name)
。请注意,id
可以是通过隐式类引入的用户定义插值器。该文档提供了json
插补器的示例
implicit class JsonHelper(val sc: StringContext) extends AnyVal {
def json(args: Any*): JSONObject = {
...
}
}
答案 3 :(得分:1)
这在当前实现中本身是不可能的:本地变量名在执行时不可用 - 可以作为调试符号保留,但也可以被剥离。 (成员变量名称是,但这不是您在此描述的内容)。