翻譯自: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