【问题标题】:What's the difference between raw string interpolation and triple quotes in scalascala中的原始字符串插值和三引号之间有什么区别
【发布时间】:2014-09-02 21:47:05
【问题描述】:

Scala 有三重引号字符串"""String\nString""" 可以在字符串中使用特殊字符而无需转义。 Scala 2.10 也出于同样的目的添加了raw"String\nString"

raw"""""""" 的工作方式有什么不同吗?他们可以为同一个字符串产生不同的输出吗?

【问题讨论】:

  • 我从下面的答案中得到的关键见解是,使用“s”插值器和“三引号”插值器可以在静态多行模板中进行替换。当我在谷歌上搜索时,我正处于编写自己的边缘,在下面看到@som-snytt 的答案并且非常兴奋。使用方法是val template = s"""Hi there, $name! You have $amount credits remaining! Code: ${code}00""" 最后一个参数上的花括号是必需的,因为紧随其后的字母数字字符。

标签: string scala string-interpolation


【解决方案1】:

查看默认插值器的源代码(可在此处找到:https://github.com/scala/scala/blob/2.11.x/src/library/scala/StringContext.scala),看起来“原始”插值器在每个字母上调用了恒等函数,因此输入的内容就是输出的内容。您会发现最大的不同是,如果您在源代码中提供包含引号字符的字符串文字,则原始插值器仍然无法工作。即你不能说

raw"this whole "thing" should be one string object"

但你可以说

"""this whole "thing" should be one string object"""

所以您可能想知道“那我为什么还要费心使用原始插值器呢?”答案是原始插值器仍然执行变量替换。所以

val helloVar = "hello"
val helloWorldString = raw"""$helloVar, "World"!\n"""

将为您提供字符串 "hello, "World"!\n",其中 \n 未转换为换行符,并在单词 world 周围加上引号。

【讨论】:

  • 谢谢,我错过了文档中说它也进行插值的部分。
  • 为了记录,scaladoc 确实说明了它的作用。 scala-lang.org/files/archive/nightly/2.11.x/api/2.11.x/…*):字符串
  • 基本上,您说raw 做了s 所做的事情。我可以s"""$literal string with substitution"""。这并不能解释为什么需要row
  • @ValentinTihomirov 不同之处在于 s 插值器仍然执行转义,因为它不知道它在三引号中。 som-snytt 的回答很好地展示和解释了这一点:stackoverflow.com/a/25633978/892445
  • 这是我刚刚遇到的一件有趣的事情。 $ 字符在插值中标记变量,在正则表达式中标记行或字符串的结尾。所以三重引号对正则表达式来说更好。
【解决方案2】:

令人惊讶的是,即使使用三引号,使用 s-interpolator 也会重新打开转义:

scala> "hi\nthere."
res5: String =
hi
there.

scala> """hi\nthere."""
res6: String = hi\nthere.

scala> s"""hi\nthere."""
res7: String =
hi
there.

s-interpolator 不知道它正在处理最初是三引号的字符串部分。因此:

scala> raw"""hi\nthere."""
res8: String = hi\nthere.

当您以其他方式(例如正则表达式)使用反斜杠时,这一点很重要:

scala> val n = """\d"""
n: String = \d

scala> s"$n".r
res9: scala.util.matching.Regex = \d

scala> s"\d".r
scala.StringContext$InvalidEscapeException: invalid escape character at index 0 in "\d"
  at scala.StringContext$.loop$1(StringContext.scala:231)
  at scala.StringContext$.replace$1(StringContext.scala:241)
  at scala.StringContext$.treatEscapes0(StringContext.scala:245)
  at scala.StringContext$.treatEscapes(StringContext.scala:190)
  at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
  at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
  at scala.StringContext.standardInterpolator(StringContext.scala:124)
  at scala.StringContext.s(StringContext.scala:94)
  ... 33 elided

scala> s"""\d""".r
scala.StringContext$InvalidEscapeException: invalid escape character at index 0 in "\d"
  at scala.StringContext$.loop$1(StringContext.scala:231)
  at scala.StringContext$.replace$1(StringContext.scala:241)
  at scala.StringContext$.treatEscapes0(StringContext.scala:245)
  at scala.StringContext$.treatEscapes(StringContext.scala:190)
  at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
  at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
  at scala.StringContext.standardInterpolator(StringContext.scala:124)
  at scala.StringContext.s(StringContext.scala:94)
  ... 33 elided

scala> raw"""\d$n""".r
res12: scala.util.matching.Regex = \d\d

【讨论】:

  • 这确实很奇怪,而不是我认为的情况。感谢您指出。
  • 我希望我能多次对此表示赞同。它只是为我节省了几个小时。我正准备编写自己的实现,却不知道我可以将“s”插值器与“三引号”插值器结合起来!一年多来,我一直在寻找这个解决方案(并且愚蠢地硬编码了好几次遮蔽胶带和绕线解决方案)。
猜你喜欢
  • 1970-01-01
  • 2012-10-16
  • 2020-03-09
  • 2011-03-27
相关资源
最近更新 更多