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版本。