翻译自:STRING INTERPOLATIONhtml
自2.10.0版本开始,Scala提供了一种新的机制来根据数据生成字符串:字符串插值。字符串插值容许使用者将变量引用直接插入处理过的字面字符中。以下例:java
val name="James" println(s"Hello,$name")//Hello,James
在上例中, s”Hello,$name” 是待处理字符串字面,编译器会对它作额外的工做。待处理字符串字面经过“号前的字符来标示(例如:上例中是s)。字符串插值的实现细节在 SIP-11 中有全面介绍。express
Scala 提供了三种创新的字符串插值方法:s,f 和 raw.json
在任何字符串前加上s,就能够直接在串中使用变量了。你已经见过这个例子:安全
val name="James" println(s"Hello,$name")//Hello,James 此例中,$name嵌套在一个将被s字符串插值器处理的字符串中。插值器知道在这个字符串的这个地方应该插入这个name变量的值,以使输出字符串为Hello,James。使用s插值器,在这个字符串中可使用任何在处理范围内的名字。
字符串插值器也能够处理任意的表达式。例如:app
println(s"1+1=${1+1}") 将会输出字符串1+1=2。任何表达式均可以嵌入到${}中。
在任何字符串字面前加上 f,就能够生成简单的格式化串,功能类似于其余语言中的 printf 函数。当使用 f 插值器的时候,全部的变量引用都应当后跟一个printf-style格式的字符串,如%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 插值器是类型安全的。若是试图向只支持 int 的格式化串传入一个double 值,编译器则会报错。例如: val height:Double=1.9d
scala>f"$height%4d" <console>:9: error: type mismatch; found : Double required: Int f"$height%4d" ^ f 插值器利用了java中的字符串数据格式。这种以%开头的格式在 [Formatter javadoc] 中有相关概述。若是在具体变量后没有%,则格式化程序默认使用 %s(串型)格式。
除了对字面值中的字符不作编码外,raw 插值器与 s 插值器在功能上是相同的。以下是个被处理过的字符串:ui
scala>s"a\nb" res0:String= a b 这里,s 插值器用回车代替了\n。而raw插值器却不会如此处理。 scala>raw"a\nb" res1:String=a\nb 当不想输入\n被转换为回车的时候,raw 插值器是很是实用的。
除了以上三种字符串插值器外,使用者能够自定义插值器。编码
在Scala中,全部处理过的字符串字面值都进行了简单编码转换。任什么时候候编译器遇到一个以下形式的字符串字面值:spa
id"string content" 它都会被转换成一个StringContext实例的call(id)方法。这个方法在隐式范围内仍可用。只须要简单得 创建一个隐类,给StringContext实例增长一个新方法,即可以定义咱们本身的字符串插值器。以下例: //注意:为了不运行时实例化,咱们从AnyVal中继承。 //更多信息请见值类的说明 implicit class JsonHelper(val sc:StringContext) extends AnyVal{ def json(args:Any*):JSONObject=sys.error("TODO-IMPLEMENT") } def giveMeSomeJson(x:JSONObject):Unit=... giveMeSomeJson(json"{name:$name,id:$id}") 在这个例子中,咱们试图经过字符串插值生成一个JSON文本语法。隐类 JsonHelper 做用域内使用该语法,且这个JSON方法须要一个完整的实现。只不过,字符串字面值格式化的结果不是一个字符串,而是一个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的成员。每一个表达式的值都将传入到JSON方法的args参数。JSON方法接受这些值并合成一个大字符串,而后再解析成JSON格式。有一种更复杂的实现能够避免合成字符串的操做,它只是简单的直接经过原生字符串和表达式值构建JSON。
字符串插值目前对模式匹配语句不适用。此特性将在2.11版本中生效。
自定义字符串插值函数:
package test.interpolator /** * 类功能描述: * * @author WangXueXing create at 19-5-3 下午9:54 * @version 1.0.0 */ case object StringU{ implicit class SLStringContext(sc: StringContext) { def sl(args: String*):String = sc.parts.mkString(",")+" : "+args.mkString(",") } }
package test.interpolator import test.interpolator.StringU._ /** * 类功能描述: * * @author WangXueXing create at 19-5-3 下午9:57 * @version 1.0.0 */ object StringTest { def main(args: Array[String]): Unit = { val i = 23 val j = "hello" val sss = sl"""24:${j}2424${i.toString}""" println(sss) } }
输出结果:
24:,2424, : hello,23