1. 概述

本教程将介绍如何在 Scala 中使用字符串插值(String Interpolation)功能。

字符串插值是一种在字符串字面量中使用占位符,并在运行时将其替换为实际值的技术

它使得字符串拼接更加直观、可读性更强,是现代编程语言中非常常见的特性。

2. s 插值器

s 插值器是最常用的字符串插值方式,它允许我们直接在字符串中嵌入变量:

val age = 30
val agePresentation = s"I am $age"
// 结果: "I am 30"

⚠️ 如果你不想让 $ 被解析为变量占位符,可以用双写 $ 来转义:

"It is about $$30"
// 结果: "It is about $30"

3. f 插值器

f 插值器是类型安全的,并且语法与 Java 中的 printf 非常相似,适合格式化输出:

val height = 1.7d
val name = "Michele"

println(f"My name is $name%s. I am $age%d years old and $height%1.2f meters tall")
// 输出: My name is Michele. I am 30 years old and 1,70 meters tall

println(f"My name is $name%d.") 
// 编译报错: type mismatch!
// found : String - required: Int

📌 所有格式化规则都与 Java 的 Formatter 类一致,可以参考 Java 格式化文档

4. raw 插值器

raw 插值器不会对字符串中的特殊字符进行转义处理,这一点与 sf 不同。

来看个例子更直观:

raw"My name is $name%s. \n $agePresentation and $height%1.2f meters"
// 输出: My name is Michele%s. \n I am 30 and 1.7%1.2f meters

f"My name is $name%s. \n $agePresentation and $height%1.2f meters tall"
/*
输出:
My name is Michele. 
I am 30 and 1.70 meters tall
*/

📌 看出区别了吗?\nraw 中不会被解释为换行符。

5. 在插值中转义双引号

有时候我们需要在插值字符串中插入双引号 ", 这时候可以借助 $ 元字符来处理。

首先定义一个双引号常量:

val DOUBLE_QUOTE: Char = '"'

然后在 s 插值中使用 ${} 包裹变量:

val actual: String = s"Hello, ${DOUBLE_QUOTE}world!${DOUBLE_QUOTE}"
val expected = "Hello, " + DOUBLE_QUOTE + "world!" + DOUBLE_QUOTE
assert(expected == actual)

✅ 正常工作!

📌 在 Scala 3 中,你甚至可以直接写 ", 而无需变量表达式:

val actual: String = s"Hello, $"world!$""

f 插值中也一样:

"Escape using metachar in f-interpolation" should "include double quote character" in {
  val actual: String = f"Hello, ${DOUBLE_QUOTE}world!${DOUBLE_QUOTE}"
  val expected = "Hello, " + DOUBLE_QUOTE + "world!" + DOUBLE_QUOTE
  assert(expected == actual)
}

6. 自定义插值器

Scala 支持自定义字符串插值器,你可以根据自己的需求实现插值逻辑。

下面是一个简单的例子:实现一个插值后自动转大写的插值器:

implicit class CustomInterpolator(val sc: StringContext) extends AnyVal {
  def custom(args: Any*): String = {
    val stringContextIterator = sc.parts.iterator
    val argsIterator = args.iterator

    val sb = new java.lang.StringBuilder(stringContextIterator.next())

    while (argsIterator.hasNext) {
      sb.append(argsIterator.next().toString)
      sb.append(stringContextIterator.next())
    }
    sb.toString.toUpperCase()
  }
}

📌 这个方法定义在 StringContext 的隐式类中,接收任意参数,并拼接后转为大写。

使用方式如下:

val testString = "well"
custom"the custom interpolator works $testString as expected"
// 输出: THE CUSTOM INTERPOLATOR WORKS WELL AS EXPECTED

编译器会自动将上面的代码展开为:

new StringContext("the custom interpolator works ", " as expected").custom(testString)

📌 这样,自定义逻辑就可以正确执行了。

7. 总结

在这篇文章中,我们详细介绍了 Scala 中三种内置的字符串插值器:

  • s: 最基础、最常用的插值方式
  • f: 类型安全、支持格式化输出
  • raw: 不转义特殊字符,适合原始字符串处理

此外,我们还展示了如何创建自定义插值器,以便满足特定业务场景的需求。

✅ 本文完整代码示例可以在这里找到:GitHub 仓库链接


原始标题:String Interpolation in Scala