http://docs.scala-lang.org/overviews/core/string-interpolation.html html
2013-1-7
(英语四级未过,借助各类词典、翻译,历时两个晚上,终于翻译完了,若有翻译错误或用词不当,欢迎指正) java
从 Scala2.10.0 开始,Scala提供一个新的机制,经过你的数据建立字符串:字符串插值(String Interpolation)。它容许用户将变量的引用直接嵌入处处理字符串字面量(processed string literals)中。例如: express
val name = "James" println(s"Hello, $name") // Hello, James
上文中,s"Hello, $name"是一个处理字符串字面量,这意味着编译器作了一些额外的工做。处理字符串字面量被表示为一个在"(双引号)以前的字符集合(原文:A processed string literal is denoted by a set of characters precedding the ". 这句没太看懂) json
Scala提供了三个开箱即用的字符串插入方法:s,f和raw 数组
在任何字符串字面量前追加s,这个字符串就容许直接包含变量。前面已经看过示例。
在示例中,$name被嵌入到一个处理字符串中,插值器s知道变量在处理字符串中的位置,并将变量的值插入其中。
字符串插值器也能够包含任意表达式(经过${})。例如: 安全
println(s"1 + 1 = ${1 + 1}")
-------------------------
实际上,s是一个case class StringContext的成员方法。
看另外一个例子: app
val name = "James" val age = 22 println(s"$name is ${age + 2} years old.")经过scalac -Xprint:cleanup输出能够获得:
new StringContext( scala.this.Predef.wrapRefArray( Array[String]{"", " is ", " years old."}.$asInstanceOf[Array[Object]]() ) ).s( scala.this.Predef.genericWrapArray( Array[Object]{name, scala.Int.box(age.+(2))} ) )从上面的抽象语法树中能够看出,编译器实际上将字符串从变量引入的地方截断,而后将字面量和变量引用分别放到两个数组中,而后从新组合(StringContext#standardInterpolator)
在任何字符串字面量前追加f,就能够创造一个简单的格式化字符串,相似于其余语言中的printf(scala里不是也有吗?)。当使用插值器f时,全部变量的引用应该跟随printf风格的格式字符串,如同%d。来看一个例子: ide
val height = 1.9d val name = "James" println(f"$name%s is $height%2.2f meters tail") // 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和插值器s类似,不一样的是它不对字符串字面量执行转义。这有一个例子: ui
scala> s"a\nb" res0: String = a b插值器s将字符\n替换成了回车符。而插值器raw不会这么作。
scala> raw"a\nb" res1: String = a\nb当你想要避免有表达式(例如\n变成回车)时,插值器raw是颇有用的。
val s1 = "a\nb" val s2 = """a\nb""" val s3 = s"a\nb" val s4 = f"a\nb" val s5 = raw"a\nb"编译后能够获得:
val s1: String = "a\nb"; val s2: String = "a\\nb"; val s3: String = new StringContext( scala.this.Predef.wrapRefArray( Array[String]{"a\\nb"}.$asInstanceOf[Array[Object]]() ) ).s(immutable.this.Nil); val s4: String = { new collection.immutable.StringOps( scala.this.Predef.augmentString("a\nb") ).format(immutable.this.Nil) }; val s5: String = new StringContext( scala.this.Predef.wrapRefArray( Array[String]{"a\\nb"}.$asInstanceOf[Array[Object]]() ) ).raw(immutable.this.Nil);从s4能够看出插值器f其实就是format方法,所以编译获得的字符串与普通字符串s1相同。
除了三个默认的字符串插值器外,用户还能够本身来定义。
在Scala中,全部处理字符串字面量都是简单的代码转换。每当编译器遇到以下形式的字符串字面量:
id"string content"编译器把它转换成StringContext实例的一个方法调用(id)。这个方法也能够在隐式做用域内。要定义本身的字符串插值,咱们须要简单地建立一个隐式类而且添加一个新方法到StringContext。这有一个例子:
// Note: We extends AnyVal to prevent runtime instantiation. See // value class guide for more info. 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 }")(呃...这里包含了隐式类和值类,都是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) } }(不过第5行仍是用StringBuilder比较合适吧)
处理后的字符串中的每一部分都暴露在StringContext的parts成员中。每一个表达式的值被传递给json方法的args参数。json方法获得它并产生一个很大的字符串,而后将其解析成JSON。一个更复杂的实现,能够避免生成这个字符串,并简单地从原始字符串和表达式的值直接构造JSON对象。
字符串插值目前没法工做在模式匹配语句中。此功能是针对Scala的2.11版本。