20.8. Klasa StringContext

W tym podrozdziale zajmiemy się dokładniej literałami przetwarzanych łańcuchów znakowych, które zostały zaprezentowane w rozdziale 3. Przypomnijmy, że literał przetwarzanego łańcucha znakowego składa się z literału znakowego zawierającego interpolowane wartości, poprzedzonego jakimś identyfikatorem. Interpolowane wartości to wyrażenia poprzedzone znakiem dolara i ewentualnie objęte znakami nawiasów klamrowych. Standardowo Scala pozwala używać takich literałów rozpoczynających się identyfikatorami s, raw i f. Tego rodzaju literały są przez kompilator zamieniane na wyrażenia tworzące instancję klasy StringContext i wywołujące na tej instancji metodę o nazwie takiej, jak identyfikator od którego rozpoczyna się literał. Wartości interpolowane są przekazywane jako kolejne argumenty tej metody. Natomiast fragmenty łańcucha znakowego znajdujące się pomiędzy tymi wartościami są przekazywane jako argumenty konstruktora klasy StringContext. Spójrzmy na literał z następującego przykładu.

scala> val (a,b,c) = (2,5,7)
a: Int = 2
b: Int = 5
c: Int = 7

scala> s"Adding $a to $b gives $c."
res0: String = Adding 2 to 5 gives 7.

Taki sam wynik możemy uzyskać jawnie tworząc instancję klasy StringContext i wywołując na niej metodę s, jak w następującym przykładzie.

scala> new StringContext("Adding "," to "," gives ",".").s(a,b,c)
res1: String = Adding 2 to 5 gives 7.

Wykorzystując opisany mechanizm oraz niejawne konwersje możemy tworzyć nowe identyfikatory, które umieszczone przed łańcuchami znakowymi spowodują ich przetworzenie. Plik NewLinesString.scala pokazuje przykład takiego nowego identyfikatora.

Plik NewLinesString.scala:
implicit class NewLinesString(sc: StringContext) {
  def nl(args: Any*): String = {
    val sb = new StringBuilder()
    var j = 0
    while (j < args.size) {
      sb append sc.parts(j)
      sb append args(j)
      sb append "\n"
      j += 1
    }
    sb append sc.parts(j)
    sb.toString
  }
}

Klasa NewLinesString definiuje niejawną konwersję, która pozwala na wywoływanie na instancjach klasy StringContext metody nl. Tym samym można wykorzystać identyfikator nl wraz z literałami przetwarzanych łańcuchów znakowych. Metoda nl tworzy napis, w którym po każdej wartości interpolowanej wstawiany jest znak nowego wiersza. Poniższy przykład ilustuje jej wykorzystanie.

scala> :load NewLinesString.scala
Loading NewLinesString.scala...
defined class NewLinesString

scala> nl"Adding $a to $b gives $c."
res2: String =
Adding 2
 to 5
 gives 7
.

Metoda nl ma dostęp do poszczególnych interpolowanych wartości za pomocą powtórzonego parametru args, natomiast do fragmentów łańcucha znakowego znajdujących się pomiędzy nimi za pomocą sekwencji zwracanej przez metodę parts instancji klasy StringContext. Metoda nl buduje wynikowy łańcuch znakowy używając instancji klasy StringBuilder, która pozwala budować łańcuch znakowy krok po kroku poprzez dodawanie kolejnych fragmentów za pomocą metody append. Metoda nl zwraca w wyniku łańcuch znakowy. Przykład z pliku ArrayString.scala pokazuje inną metodę, która zwraca wartość typu innego niż String.

Plik ArrayString.scala:
implicit class ArrayString(sc: StringContext) {
  def arr(args: Any*): Array[String] = sc.parts(0).split(" ")
}

Klasa ArrayString definiuje niejawną konwersję, która pozwala na wywoływanie na instancjach klasy StringContext metody arr. Metoda arr interpretuje pierwszy z łańcuchów znakowych zwracanych przez metodę parts jako sekwencję wartości oddzielonych spacjami i zwraca te wartości w tablicy. Poniższy przykład pokazuje wykorzystanie metody.

scala> :load ArrayString.scala
Loading ArrayString.scala...
defined class ArrayString

scala> arr"Hello World !"
res3: Array[String] = Array(Hello, World, !)

Ponieważ metoda arr wykorzystuje jedynie pierwszy element sekwencji zwracanej przez metodę parts, w literałach używających tej metody nie należy umieszczać interpolowanych wyrażeń, ponieważ ich wartości zostaną zignorowane, jak w poniższym przykładzie.

scala> arr"Adding 2 to $b gives $c."
res4: Array[String] = Array(Adding, 2, to)

Język programowania Scala Wydanie 2. Copyright © Grzegorz Balcerek 2016

Licencja Creative Commons

Ten utwór jest dostępny na licencji Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowe.

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.