带有嵌入变量的现有String上的Scala String Interpolator

时间:2016-04-15 19:41:45

标签: scala

我可能会遗漏Scala字符串插值机制的基本内容。我想做什么:

// this could come from a config file, string here to demo
val brown = "BROWN"
val cow = "Moo"
val replaceInMe = "How Now ${brown} ${cow}"

//this does what I eventually want:
val output = s"How Now ${brown} ${cow}"

//But, since the variables 'brown' and 'cow' are defined,
//I really wold like to be able to do something like:
val output = s(replaceInMe) 

这甚至可能吗?

编辑:根据下面的第一个答案,必须将变量replaceInMe作为输入。在这里我将它定义为一个String,但它实际上是一个从配置文件读取的行。

3 个答案:

答案 0 :(得分:5)

没有。 documentation清楚地表明您只能使用字符串文字,而不能使用任何字符串对象。

这是因为当编译器看到:

s"How Now ${brown} ${cow}"

它将其转换为:

new StringContext("How Now ", " ", "").s(brown, cow)

编译器不能使用任意标识符执行此操作,因为这些值很可能在运行时设置,而不是在编译时设置。想象一下,replaceInMe是从外部文件中提取的值。外部文件中的字符串如何可能知道程序中的运行时变量?如果它们没有被定义怎么办?使用字符串插值,这是通过编译错误处理的,这显然不会在运行时发生。在运行时,您需要另一种方法来处理缺失值。

最好使用某种配置库来处理这个问题。

答案 1 :(得分:2)

但等等,还有更多!它是一个编译器一个模板引擎!

scala> import javax.script._
import javax.script._

scala> val se = new ScriptEngineManager().getEngineByName("scala")
se: javax.script.ScriptEngine = scala.tools.nsc.interpreter.Scripted@2a742aa2

scala> val animal = new { override def toString = "cow" } // some value
animal: AnyRef = cow

scala> se.put("animal", animal)

scala> val template = "I see a $animal"
template: String = I see a $animal

scala> se.eval(s"""s"$template, she said."""")
res1: Object = I see a cow, she said.

,或者

scala> val sc = se.asInstanceOf[ScriptEngine with Compilable]
sc: javax.script.ScriptEngine with javax.script.Compilable = scala.tools.nsc.interpreter.Scripted@2a742aa2

scala> val cs = sc.compile(s"""s"$template, she said."""")
cs: javax.script.CompiledScript = scala.tools.nsc.interpreter.Scripted$WrappedRequest@1dba7721

scala> cs.eval()
res4: Object = I see a cow, she said.

scala> val ctx = sc.createBindings()
ctx: javax.script.Bindings = javax.script.SimpleBindings@1ad28f2       

scala> ctx.put("animal", "frog")
res5: Object = null

scala> cs.eval(ctx)
res6: Object = I see a frog, she said.

只是为了表明“编译时间”是相对的:

scala> val cs = sc.compile("""s"There's no such $thing in scope."""")
<console>:12: error: not found: value thing
       s"There's no such $thing in scope."
                          ^
javax.script.ScriptException: compile-time error
  at scala.tools.nsc.interpreter.Scripted.scala$tools$nsc$interpreter$Scripted$$$anonfun$7(Scripted.scala:113)
  at scala.tools.nsc.interpreter.Scripted$DynamicContext.apply(Scripted.scala:38)
  at scala.tools.nsc.interpreter.Scripted.compile(Scripted.scala:101)
  at scala.tools.nsc.interpreter.Scripted.compile(Scripted.scala:124)
  ... 30 elided

答案 2 :(得分:0)

是的,这是可能的。 只需在replaceInMe之前定义val&#39的棕色和牛,就像:

在您的情况下,它不起作用,因为您无法在评估后更改replaceInMe。它是一种价值类型。

    val brown = "BROWN"
    val cow = "Moo"
    // this could come from a config file, string here to demo
    val replaceInMe = s"How Now ${brown} ${cow}"
    println( replaceInMe )

了解更多详情: http://docs.scala-lang.org/overviews/core/string-interpolation.html