[AD] Scalaアプリケーションの開発・保守は合同会社ミルクソフトにお任せください
リテラルとは何でしょうか?
この記事ではリテラルについて解説します。
リテラルとはソースコードに値を直接記述したもの
リテラルとはプログラムのソースコードの中に特定のデータ型の値を直接記述したものです。
例えば、ソースコードの中に記述した123
は整数値のリテラル表記です。
また、多くのプログラミング言語では文字列をダブルクォーテーション("
)で囲んで記述します。(例: "文字列"
)
このように値をソースコードの中に記述するために定められている書式もリテラルです。
Scalaで利用できるリテラル表記
Scalaでは以下のリテラル表記が使用できます。
- 数値
- 真偽値
- 文字
- 文字列
- 関数
- タプル
数値のリテラル表記
数値のリテラル表記には整数値と浮動小数点があります。
整数値のリテラル表記
整数値のリテラル表記はその名の通りプログラム中に記述した整数値です。
整数値は10進数または16進数で記述します。
16進数で記述する場合は整数値の前に0x
をつけて記述します。
- 10進数で記述した場合
val x = 123
- 16進数で記述した場合
val x = 0x7b
整数値の型は以下の4つです。
Int
Long
Byte
Short
通常、プログラム中に記述した整数値はInt
型の値です。
整数値の後ろにL
はまたは、l
を記述した場合は、Long
型の値になります。
l
は非推奨です。L
を利用するのが良いでしょう。
Int
の例
val x = 123 val y = 0x7b
Long
の例
val x = 123L val y = 0x7bL
記述したリテラルの型がByte
、Short
のどれかに予測できて、かつ値がその型の範囲内であればその型に変換します。
以下の例では変数の型を宣言しているため指定した整数値は変数の型に変換し、変数に設定されます。
Byte
の例
val x: Byte = 123 val y: Byte = 0x7b
Short
の例
val x: Short = 123 val y: Short = 0x7b
浮動小数点のリテラル表記
浮動小数点のリテラル表記はFloat
またはDouble
です。
浮動小数点は以下の方法で記述します。
- 小数点を含む数値
val x = 123.456
- 指数表現
val x = 1.23456e2
- 末尾に
d
またはD
をつける(Double
)
val x = 123d
- 末尾に
f
またはF
をつける(Float
)
val x = 123f
末尾に何もつけない場合はDouble
になります。
真偽値のリテラル表記
真偽値のリテラルは、Boolean
型のtrue
またはfalse
です。
文字のリテラル表記
文字リテラルはChar
型のシングルクォーテーション('
)で囲まれた単一の文字です。
指定できる文字は任意のユニコード文字です。
- 例
'a', '\u0041', '\n'
また、以下のように整数値で指定することもできます。
val c: Char = 123
文字列のリテラル表記
文字列リテラルはString
型のダブルクォーテーション("
)で囲まれた文字のシーケンスです。
バックスラッシュ(\
) + 文字で改行(\n
)等のエスケープ文字を含めることができます。
println("この文字列は\n3行に分けて\n表示されます。")
以下のように文字列中の\n
の位置で改行して表示されます。
この文字列は 3行に分けて 表示されます。
生文字リテラル
ダブルクォテーション("
)3つで囲むと生文字リテラルになります。
生文字リテラルではバックスラッシュ(\
)はエスケープ文字として扱われません。
println("""C:\Users\hogehoge\Desktop""")
以下のようにバックスラッシュ(\
)がそのまま表示されます。
C:\Users\hogehoge\Desktop
また、文字列の途中で改行すると改行を含んだ文字列になります。
println("""この文字列は 3行に分けて 表示されます。""")
以下のように改行されて表示されます。
この文字列は 3行に分けて 表示されます。
上記の例では、2行目と3行目の左側の空白もそのまま文字列に含まれています。
空白を取り除きたい場合は、以下のようにstripMargin
メソッドを使用します。
println("""この文字列は |3行に分けて |表示されます。""".stripMargin)
stripMargin
メソッドを使用すると、以下のように2行目、3行目の左側の空白は除かれて表示されます。
この文字列は 3行に分けて 表示されます。
加工文字列リテラル
加工文字リテラルを使用すると文字列内に直接変数の参照を埋め込むことができます。
加工文字リテラルは文字列の前に特定の文字(補完子)を置くことで表現します。
Scalaでは以下の3つの補完子を提供します。
- s補完子
- f補完子
- raw補完子
また、利用者が任意の補完子(カスタム補完子)を用意することができます。
s補完子
文字列リテラルの先頭にs
を置くことで文字列中に変数を記述することができます。
val name = "Taro" println(s"Hello $name.")
以下のように文字列中に埋め込んだ変数「name」を評価した値が表示されます。
Hello Taro.
また、以下のように式を記述することもできます。
println(s"1 + 1 = ${1 + 1}")
式を評価した値が表示されます。
1 + 1 = 2
f補完子
文字列リテラルの先頭にf
を置くことで文字列中に埋め込んだ変数の書式を指定することができます。
以下のように変数の後ろに「%
書式」の形式で記述します。
省略した場合は「%s
」が適用されます。
%s
は文字列です。
val name = "Mt. Fuji" val height = 3776.12 println(f"$name is $height%4.1fm height.")
変数「height」は小数点以下が2桁のDouble
ですが、書式では小数点以下を1桁に指定しているため、四捨五入して小数点1桁で表示されます。
Mt. Fuji is 3776.1m height.
f補完子で指定する書式はJavaの機能を使用しています。
指定できる書式の詳細は以下を参照してください。
raw補完子
「raw補完子」は文字列リテラル内に変数を埋め込むことができる点は「s補完子」と同じです。
文字列リテラル内でエスケープを実行しない点が、「s補完子」との違いです。
以下のように「s補完子」を使用した場合は文字列リテラル内の\n
は改行文字に置換されます。
val name = "Hanako" println(s"Hello \n $name.")
Hello Hanako.
raw補完子の場合はも維持列リテラル内の\n
は改行文字に置換されずにそのまま表示されます。
val name_2 = "Hanako" println(raw"Hello \n $name_2.")
Hello \n Hanako.
カスタム補完子
前述の3つの補完子の他に利用者が独自の補完子を定義することができます。
以下の例ではカスタム補完子my
を使用して値を[]
で囲んで表示しています。
val x = 123 println(my"x=$x")
x=[123]
このようなことができる理由を説明します。
ダブルクォテーション("
)の前に文字を記述すると、Scalaのコンパイラは該当するコードをStringContext
クラスのインスタンスへのメソッド呼び出しに変換します。
前述の補完子my
を使用したコードは以下のように変換されます。
new StringContext("x=", "").my(x)
もちろんStringContext
クラスにはmy
メソッドは存在しません。
そのため、利用者はStringContext
クラスのmy
メソッドを呼び出した場合の処理を追加する必要があります。
この処理はimplicit
クラスを使用して記述します。
補完子my
を処理するコードは以下のとおりです。
implicit class MyHelper(val sc: StringContext) extends AnyVal: def my(args: Any*): String = val strings = sc.parts.iterator val expressions = args.iterator val str = new java.lang.StringBuffer(strings.next()) while(expressions.hasNext) str.append("[") str.append(expressions.next().toString()) str.append("]") str.append(strings.next()) str.toString()
このようにすることで利用者が独自の補完子を追加できるようにしています。
関数のリテラル表記
Scalaの関数は以下のように右辺のパラメータリストと=>、左辺の式またはブロックで構成されます。
これを関数リテラルと呼びます。
(パラメーターリスト) => 式 or ブロック
以下のSeq
のメソッドの引数に関数リテラルを記述する例を見てみます。
val list = Seq(1, 2, 3, 4, 5)
以下の例ではSeq
のmap
メソッドの引数に関数リテラルを記述しています。
val result = list.map((x: Int) => x * 2) println(result)
map
メソッドに渡す関数の引数の型は省略可能です。
これは、コンパイラによりInt
型に推測可能なためです。
val result_2 = list.map(x => x * 2) println(result_2)
また、引数が関数内で1度だけ使われる場合は、引数の宣言を省略することができます。
val result_3 = list.map(_ * 2) println(result_3)
実行結果は以下のとおりすべて同じです。
List(2, 4, 6, 8, 10)
値を返さない場合がある関数のリテラル表記
関数リテラルの例をもう1つ紹介します。
以下の例では、Seq
のcollect
メソッドを使用して要素のうち偶数の値を抽出しています。
collect
メソッドに渡している関数は、渡された引数を2で割った結果が0(偶数)の場合のみ値を返しています。
このように値を返さない場合がある関数をPartialFunction
と言います。
val result_4 = list.collect({case x if x % 2 == 0 => x}) println(result_4)
実行結果は以下のようになります。
List(2, 4)
タプルのリテラル表記
タプルとは決まった数の要素を含む値です。
以下のように要素をカッコで囲んで記述するとタプルのリテラル表記となります。
val t = (1, 2, 3, 4)
また、要素の数が2つのタプルは以下のように記載することができます。
val t = ("key" -> "value")
val t = ("key" → "value")
→
は非推奨なので使わないほうが良いでしょう。
Scala 3で廃止予定のリテラル表記
シンボルのリテラル表記
シンボルリテラルはシングルクォーテーション('
)で始まる文字列です。
以下のように記述します。
val symbol = 'symbol
同じ名前を持つシンボルは常に同じオブジェクトを参照します。
シンボルリテラルは利用頻度が低いためScala 3で廃止されます。
シンボルリテラルは使用しないほうが良いでしょう。
XMLのリテラル表記
XMLリテラルはその名の通りXMLを表す文字列です。
Scalaではソースコード上に直接XMLを記述することができます。
val xml = <html> <head> <title>タイトル</title> </head> <body> <p>本文</p> </body> </html>
XMLリテラルを扱うためのライブラリ(scala-xml
)は2.11で標準ライブラリから分離されました。
XMLリテラルを使う場合は、scala-xml
をsbtの設定ファイルに記述する必要があります。
libraryDependencies += "org.scala-lang.modules" %% "scala-xml" % "1.3.0"
また、XMLリテラル表記はScala 3で廃止されます。
Scala 3ではXMLリテラル表記の代わりに「xml補完子」が追加される予定です。
XMLリテラルは使用しないほうが良いでしょう。