Scala 点滴:String & String Interpolation

String:

Scala中的String类使用的就是Java的String.class;所以,用法跟Java相同。但是Scala中加入了StringOps类扩展了String,有一些很有用的方法。

几个需要注意的是:

  1. "a" * 2    返回:"aa":字符串 * 2。
  2. """ She said: "Hey,geys." And then... """:原生字符串,其中可有任意符号。

String interpolation:

官方文档:String Interpolation

Introduction:

从 Scala2.10.0 开始,Scala提供一个新的机制,通过你的数据创建字符串:字符串插值(String Interpolation)。它允许用户将变量的引用直接嵌入到处理字符串字面量(processed string literals)中。例如:

    val name = "James"
    println(s"Hello, $name") // Hello, Jameshttp://write.blog.csdn.net/postedit/44498133

上文中,s"Hello, $name"是会被 s 处理的字符串字面量,这意味着编译器会对这个字面量做一些额外的工作。s 处理字符串字面量表示为一个在"(双引号)之前的字符集合。

Usage:

Scala提供了三个开箱即用的字符串插入方法:sfraw


插值器:s

预先准备s可以在任意的字符串字面量中直接使用变量。例如:

    val name = "James"
    println(s"Hello, $name") // Hello, James
这里 $name 是个嵌入在 s 处理的字符串。s插值器知道字符串中变量name的值,返回Hello, James

字符串插值器也可以包含任意表达式(通过${})。例如:

    println(s"1 + 1 = ${1 + 1}")

插值器:f

在任何字符串字面量前追加f,就可以创造一个简单的格式化字符串,类似于其他语言中的printf。当使用插值器f时,所有变量的引用应该跟随printf风格的格式字符串,如同%d。来看一个例子:

    val height = 1.9d
    val name = "James"
    println(f"$name%s is $height%2.2f meters tall") // James is 1.90 meters tall
插值器f是类型安全的。如果你试图传递一个只能工作于整数的格式化字符串,却又传了一个浮点数,编译器会发出一个错误。例如:

    val height: Double = 1.9d
    scala> f"$height%4d"
    <console>:9: error: type mismatch;
    found : Double
    required: Int
    f"$height%4d"
    ^
插值器f利用Java的字符串格式工具(The f interpolator makes use of the string format utilities available from Java.)。字符%后允许的格式在Formatter javadoc中有概述。如果一个变量没有定义格式器,那么就假设它是%s(String)(即f"$name"等同于f"$name%s")。


插值器:raw

插值器raw和插值器s相似,不同的是它不对字符串字面量执行转义。这有一个例子:
    scala> s"a\nb"
    res0: String =
    a
    b
插值器s将字符\n替换成了回车符。而插值器raw不会这么做。

scala> raw"a\nb"
res1: String = a\nb
当你想要避免有表达式(例如\n变成回车)时,插值器raw是很有用的。


Advanced Usage:

在Scala中,所有处理字符串字面量都是简单的代码转换。每当编译器遇到如下形式的字符串字面量:

id"string content"

编译器把它转换成StringContext实例的一个方法调用(id)。这个方法也可以在隐式作用域内。要定义自己的字符串插值,我们需要简单地创建一个隐式类并且添加一个新方法到StringContext。这有一个例子:

<code class="scala comments">// Note: We extends AnyVal to prevent runtime instantiation. See</code><div class="container"><div class="line number2 index1 alt1"><code class="scala comments">// value class guide for more info.</code></div><div class="line number3 index2 alt2"><code class="scala keyword">implicit</code> <code class="scala keyword">class</code> <code class="scala plain">JsonHelper(</code><code class="scala keyword">val</code> <code class="scala plain">sc</code><code class="scala keyword">:</code> <code class="scala plain">StringContext) </code><code class="scala keyword">extends</code> <code class="scala plain">AnyVal {</code></div><div class="line number4 index3 alt1"><code class="scala spaces">    </code><code class="scala keyword">def</code> <code class="scala plain">json(args</code><code class="scala keyword">:</code> <code class="scala plain">Any*)</code><code class="scala keyword">:</code> <code class="scala plain">JSONObject </code><code class="scala keyword">=</code> <code class="scala plain">sys.error(</code><code class="scala string">"TODO - IMPLEMENT"</code><code class="scala plain">)</code></div><div class="line number5 index4 alt2"><code class="scala plain">}</code></div><div class="line number6 index5 alt1"><code class="scala keyword">def</code> <code class="scala plain">giveMeSomeJson(x</code><code class="scala keyword">:</code> <code class="scala plain">JSONObject)</code><code class="scala keyword">:</code> <code class="scala plain">Unit </code><code class="scala keyword">=</code> <code class="scala plain">...</code></div><div class="line number7 index6 alt2"><code class="scala plain">giveMeSomeJson(json</code><code class="scala string">"{ name: $name, id: $id }"</code><code class="scala plain">)</code></div></div>
(呃...这里包含了隐式类和值类,都是Scala2.10的新特性。稍后可能会把这两个特性也翻译一下——如果看得懂的话。另外,implicit只能声明内部类,否则会报错,这点还不确认,等看完隐式类再说。)

在这个例子中,我们试图使用字符串插值创建一个JSON文字语法。隐式类JsonHelper必需在作用域内才可以使用这个语法,并且json方法需要完整地实现。无论如何,这个格式化字符串的结果将不是一个字符串,而是JSONObject。
当编译器遇到字符串json"{ name: $name, id: $id }",它将字符串重写为如下表达式:

new StringContext("{ name:", ",id: ", "}").json(name, id)
然后隐式类用于将它重写成如下形式:
new JsonHelper(new StringContext("{ name:", ",id: ", "}")).json(name, id)
这样,json方法可以访问原始块字符串,并将每一个表达式作为值。一个简单的方法实现可以是:
implicit class JsonHelper(val sc: StringContext) extends AnyVal {
    def json(args: Any*): JSONObject = {
        val strings = sc.parts.iterator
        val expressions = args.iterator
        var buf = new StringBuffer(strings.next)
        while(strings.hasNext) {
            buf append expressions.next
            buf append strings.next
        }
        parseJson(buf)
    }
}
处理后的字符串中的每一部分都暴露在StringContext的parts成员中。每个表达式的值被传递给json方法的args参数。json方法得到它并产生一个很大的字符串,然后将其解析成JSON。一个更复杂的实现,可以避免生成这个字符串,并简单地从原始字符串和表达式的值直接构造JSON对象。

限制

字符串插值目前无法工作在模式匹配语句中。此功能是针对Scala的2.11版本。












阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页