轉載自:http://songkun.me/2018/05/14/scala-string-ops/
String
源碼剖析
Scala 中的 String
其實僅僅是 java.lang.String
的別名,在 scala.Predef
中可以找到其定義:
1 |
type String = java.lang.String |
明明 Scala 的字符串有很多非常有用的函數啊,難道都是錯覺?
實際上 scala.Predef
中還有一個與 String
關係重大的隱式函數:
1 |
@inline implicit def augmentString(x: String): StringOps = new StringOps(x) |
該函數將 String
值隱式轉換爲 StringOps
值,StringOps
源碼如下:
1 2 3 4 |
final class StringOps(override val repr: String) extends AnyVal with StringLike[String] { ... override def apply(index: Int): Char = repr charAt index override def slice(from: Int, until: Int): String = ??? |
除了 slice
函數以外,其餘函數我們也沒怎麼用過,還得繼續深入一層,看下 StringLike
的源碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
trait StringLike[+Repr] extends Any with scala.collection.IndexedSeqOptimized[Char, Repr] with Ordered[String] { self => override def mkString = toString override def slice(from: Int, until: Int): e def * (n: Int): String = def stripLineEnd: String def linesWithSeparators: Iterator[String] def capitalize: String def stripPrefix(prefix: String) def stripSuffix(suffix: String) def replaceAllLiterally(literal: String, replacement: String): String def stripMargin(marginChar: Char): String def stripMargin: String = stripMargin('|') ... } |
臥槽,我們平時常用的函數都在這裏啊,原來如此!
其實這是 Scala 的一種常見設計模式,即 Type Class 模式(源於 Haskell),通過 implicit
轉換函數,在不修改第三方庫源碼(java.lang.String
)的條件下,實現對第三方庫功能增強,用在 String
這裏非常適合。
常用函數
下面是一些 Scala String
的常用函數,非常方便。
多行字符串
使用 """
包裹即可實現多行字符串,比 Java 方便太多:
1 2 3 4 5 6 |
val s = """ This is a scala line """ |
輸出如下:
1 2 3 4 |
s: String = This is a scala line |
若想要 去掉 每行開頭的空字符串,可以用 stripMargin
:
1 2 3 4 5 6 |
val a = """ |This is // 使用默認分割符 | |a scala |line """.stripMargin |
輸出如下:
1 2 3 4 |
a: String = This is a scala line |
stripMargin
函數實現如下:
1 2 3 4 5 6 |
/** For every line in this string: * * Strip a leading prefix consisting of blanks or control characters * followed by `|` from the line. */ def stripMargin: String = stripMargin('|') |
因此,不必非要用 |
分割符,可以使用自定義的分隔符:
1 2 3 4 5 6 |
val b = """ #This is #a scala #line """.stripMargin('#') |
輸出與使用 |
完全相同:
1 2 3 4 |
b: String = This is a scala line |
字符串插值
字符串插值是通過將
String
隱式轉換爲StringContext
實現的,Scala 允許我們自定義字符串插值器。
1. s 插值
在任意字符串前面加 s
後,就可以在該字符串中使用 變量 和 表達式 了:
1 2 3 |
val a = 111 val b = 6 val c = s"a + b = ${a + b}" |
2. f 插值
在字符串前面加 f
,以簡單格式化字符串:
1 2 3 |
val a = 111.111111 val b = 6 val c = f"a * b = ${a * b}%2.2f" |
%2.2f
指定格式
3. raw 插值
對字符串中的字符 不做編碼,其他與 s 插值相同。
若有 s 插值如下:
1 2 3 4 5 6 7 |
val a = 111 val b = s"b = \n$a" // 輸出 a: Int = 111 b: String = b = 111 |
若不想對 \n
轉義,則可用 raw 插值:
1 2 3 4 5 6 |
val a = 111 val b = raw"b = \n$a" // 輸出 a: Int = 111 b: String = b = \n111 |
strip
去掉字符串前後綴:
1 |
". Hello .".stripPrefix(".").stripSuffix(".").trim |