Scala 插入式 字符串拼接

2019-05-05 15:52:58 | 编辑 | 添加

Scala 字符串拼接的方式,是可插入式的字符串拼接方式,这和很多前端框架的模板式拼接内容是一致的。这里将对其进行更深层次地分析。

假如某一字符串的形式为s"foo ${bar}",那么表达式bar 将会被转化为字符串并被插入到原字符串中的$"{bar}" 的位置中。假如表达式bar 返回的不是字符串,而是某一类型的实例,那么只要该实例中定义toString 方法,系统便会调用该方法将该实例转化成字符串。如果bar 表达式返回值无法转换成字符串,那么程序将会报错。

如果bar 是一个变量引用,那么可以省略字符串中的大括号。如下所示:

val name = "Buck Trends"
println(s"Hello, $name")


如果想在可插入字符串中输入美元符,那么请连续输入两个美元符$$。


Scala 中存在两类可插入字符串。第一类采用printf 格式,这类可插入字符串以f 为前缀。第二类也被称为“原生的”可插入字符串,这类字符串并不会对像\n 这样的逃逸字符串进行扩展。


假设我们正在生成财务报表,希望浮点数只显示到小数点后两位4。那么可以编写如下代码:

val gross = 100000F
val net = 64000F
val percent = (net / gross) * 100
println(f"$$${gross}%.2f vs. $$${net}%.2f or ${percent}%.1f%%")

最后一行代码将输出下列结果:

$100000.00 vs. $64000.00 or 64.0%

采用printf 格式时,Scala 会调用Java 的Formatter 类。这类字符串中嵌入的表达式与之前代码使用的语法相同,均为$"{...}",不过在编写时printf 格式指令与${...} 之间不应有空格.


在该示例中,为了打印出一个美元符号,我们使用了两个美元符$$;同时使用了两个百分号%% 以打印出一个百分号。表达式${gross}%.2f 会格式化gross 的变量值,保留其小数点后两位数字。


可插入字符串中的变量类型必须与其格式吻合,为此Scala 会执行一些隐式转化。下面列出的代码试图在浮点数语境中使用Int 表达式,Scala 允许这种操作并会在整数的小数点后添加两个0。而第二个表达式则尝试将Double 类型值展现为Int 类型,不过这次尝试会导致编译错误:

scala> val i = 200
i: Int = 200
scala> f"${i}%.2f"
res4: String = 200.00
scala> val d = 100.22
d: Double = 100.22
scala> f"${d}%2d"
<console>:9: error: type mismatch;
found : Double
required: Int
f"${d}%2d"


顺便提一下, 调用Java 静态方法String.format将按照printf 的格式对字符串格式化。该方法的输入参数包含了格式字符串以及一组用于替代格式字符串的变量列表。String.format 方法还有另外一个版本,该版本中的第一个参数代表字符串的区域设置(该参数为Locale 类型)。


Scala 编译器会在某些语境中对Java 字符串进行封装并提供一些额外的方法,这些定义在scala.collection.immutable.StringLike(http://www.scala-lang.org/api/current/scala/collection/immutable/StringLike.html)中。这些额外提供的方法中包含了一个叫作format的实例方法。你可以对一个格式化字符串调用该方法并传入需要插入到该字符串中的参数列表。具体如下:


scala> val s = "%02d: name = %s".format(5, "Dean Wampler")
s: String = "05: name = Dean Wampler"

在该示例中,我们希望能输出两位数整数并在小数点添加两个零。最后一类内置的字符串插入器被称为“原生”(raw)插入器,该插入器不会对控制字符进行扩展,具体请参阅下面两个示例。

scala> val name = "Dean Wampler"
name: String = "Dean Wampler"
scala> s"123\n$name\n456"
res0: String =
123
Dean Wampler
456
scala> raw"123\n$name\n456"
res1: String = 123\nDean Wampler\n456


最后提一下,其实我们可以自定义字符串插入器,不过在此之前,我们需要掌握更多的关于隐式转换(implicit)的知识。