在Scala 2.10中的String Interpolation中获取参数名称

时间:2013-02-11 23:00:07

标签: string scala scala-2.10 string-interpolation

从scala 2.10开始,可以进行以下插值。

val name = "someName"
val interpolated = s"Hello world, my name is $name"

现在也可以定义自定义字符串插值,您可以在此处的“高级用法”部分的scala文档中看到http://docs.scala-lang.org/overviews/core/string-interpolation.html#advanced_usage

现在,我的问题是......有没有办法在插值之前获取原始字符串,包括任何插值变量名,来自为字符串定义新插值的隐式类内部?

换句话说,我希望能够以这样的方式定义插值x,当我调用时

x"My interpolated string has a $name"

我可以完全按照上面的说明获得字符串,而无需替换插值内的$ name部分。

编辑:快速说明,我想这样做的原因是因为我想获取原始字符串并将其替换为另一个字符串,国际化字符串,然后替换变量值。这是我想要获得原始字符串而不对其执行插值的主要原因。

提前致谢。

3 个答案:

答案 0 :(得分:3)

由于Scala的字符串插值可以处理${}中的任意表达式,因此在将参数传递给格式化函数之前,它必须评估参数。因此,设计不可能直接访问变量名。正如Eugene所指出的,可以通过使用宏来获取普通变量的名称。不过,我不认为这是一个非常可扩展的解决方案。毕竟,你将失去评估任意表达式的可能性。例如,在这种情况下会发生什么:

x"My interpolated string has a ${"Mr. " + name}"

您可以使用宏提取变量名称,但任意表达式可能会变得复杂。我的建议是:如果变量的名称在字符串插值中应该有意义,请将其作为数据结构的一部分。例如,您可以执行以下操作:

case class NamedValue(variableName: String, value: Any)

val name = NamedValue("name", "Some Name")

x"My interpolated string has a $name"

对象以Any*传递给x。因此,您现在可以在NamedValue内匹配x,并且您可以根据“变量名称”执行特定操作,该变量名称现在是数据结构的一部分。您可以使用类型层次结构,而不是显式存储变量名称,例如:

sealed trait InterpolationType
case class InterpolationTypeName(name: String) extends InterpolationType
case class InterpolationTypeDate(date: String) extends InterpolationType

val name = InterpolationTypeName("Someone")
val date = InterpolationTypeDate("2013-02-13")
x"$name is born on $date"

同样,在x中,您可以匹配InterpolationType子类型并根据类型处理事物。

答案 1 :(得分:2)

似乎不可能。字符串插值看起来像编译功能,将示例编译为:

StringContext("My interpolated string has a ").x(name)

正如您所看到的,$name部分已经消失。当我查看StringContexthttps://github.com/scala/scala/blob/v2.10.0/src/library/scala/StringContext.scala#L1

的源代码时,我变得非常清楚

答案 2 :(得分:1)

如果将x定义为宏,那么您将能够看到编译器生成的desugaring树(如@EECOLOR所示)。在该树中,“name”参数将被视为Ident(newTermName(“name”)),因此您将能够从那里提取名称。请务必查看docs.scala-lang.org上的宏观和反射指南,以了解如何编写宏并使用树。