Scalaの式とブロックについて解説

Scala 3 (Dotty 0.26.0-RC1) 2.13.3 2.12.12
最終更新:2020年5月19日

[AD] scalapediaでは記事作成ボランティアを募集しています

この記事では、式とブロック式(以降、ブロックと記載)について解説します。
また、Scalaの制御構文を例に、式やブロックの使い方を解説します。

式、文、ブロックについて

式は評価すると値となる

プログラムを構成する構文のうち、評価すると数値や文字など何かしらの値となるものを式といいます。
以下はすべて式です。

  • 1 + 1
  • hogehoge
  • if(x < 10) x * 2

文は評価しても値とならない

プログラムを構成する構文のうち、評価しても値とならないもののことを文といいます。
Scalaでは、valvarが文になります。
val s: String = "hogehoge"は、「変数 s」を定義して、sに文字列: ”hogehoge”を設定しますが、この定義自体は値にはなりませんので、文です。

ブロックは評価すると値となる

次にブロックについて説明します。
波括弧{}で囲んだ1つ以上の式のことをブロックといいます。
波括弧{}内に記載した最後の式を評価した値が、ブロックの値になります。

以下の例では、ブロック内の最後の式(a + b)を評価した値が、ブロックの値になります。

val x = { val a = 1 val b = 2 a + b } println(x)

実行結果は、以下のように3が出力されます。

3

()、{}の違いについて

では、括弧()で式を囲んだ場合は、どのような動作になるでしょうか?
括弧()で式を囲んだ場合も、式を評価した値となりますが、波括弧{}と違って、式は1つだけしか書くことができません。

ブロックの例のように、abを足した値を求める場合、以下のように記載することはできますが、

val a = 1 val b = 2 val x = (a + b)

以下のように書くことはできません。

val x = ( val a = 1 val b = 2 a + b )

このように書いた場合は、コンパイルエラーになります。

error: illegal start of simple expression

制御構文は値を返す

次に制御構文について説明します。
Scalaの制御構文はすべて式のため、値を返します。

一見、値を返さないように見えるwhiledo-whileなどもUnitを返します。
Unitとは、戻り値としては意味がないことを示すものです。

次からは、Scalaで使用できる制御構文を紹介します。
ここでは概要のみを紹介しますので、詳細は各制御構文の説明を参照してください。

ifの戻り値

ifは、以下のように記述します。

Scala
if(条件式) 式1 else 式2

条件式がtrueの場合は、式1を評価した値がifの値になります。
条件式がfalseの場合は、式2を評価した値がifの値になります。

以下の例では、20歳未満の場合には、「○○さんは、お酒を飲んではいけません。」を返し、20歳以上の場合には、「○○さんは、お酒を飲めます。」を返します。

def whoCanDrink(person: Person): String = { if(person.age < 20) { s"${person.name}さんは、お酒を飲んではいけません。" } else { s"${person.name}さんは、お酒を飲めます。" } }

では、定義した関数を呼び出してみます。

Taroさんは、20歳なのでifの値は、「Taroさんは、お酒を飲めます。」となります。

println(whoCanDrink(Person(20, "Taro")))

出力結果は、以下のとおりです。

Taroさんは、お酒を飲めます。

Hanakoさんは、20歳に満たないのでifの値は、「Hanakoさんは、お酒を飲んではいけません。」となります。

println(whoCanDrink(Person(19, "Hanako")))

出力結果は、以下のとおりです。

Hanakoさんは、お酒を飲んではいけません。

上記例では、式1、式2には、ブロックを使用していますが、ブロックの他に式、括弧を指定することができます。
ただし、式や括弧は三項演算として利用する場合にのみ使用し、通常はブロックを使用するのが良いでしょう。

if式について、詳しい使い方は以下の記事を参照してください。

forの戻り値

forの基本的な構文は、以下のようになります。

Scala
for(ジェネレーター) 本体

ジェネレータと本体には、式やブロックを指定できます。

次の例では、ifで登場したTaroさんとHanakoさんからなるリストに対して、forを適用しています。
personsの要素ごとに本体を適用して、Seq[String]型の値を取得しています。

val persons = Seq( Person(20, "Taro"), Person(19, "Hanako") ) val result: Seq[String] = for(p <- persons) yield s"${p.name}さんは、${p.age}歳です。" result.foreach(e => println(e))

実行結果は、以下のようになります。

Taroさんは、20歳です。 Hanakoさんは、19歳です。

上記例では、本体の前にyieldを記述しているため、本体を評価した結果から値を生成していますが、本体の前にyieldを記述しない場合は、返す値がないため、forの値はUnitとなります。

forについては、その他に便利な利用方法が多数あります。
詳細は、以下の記事を参照してください。

matchの戻り値

matchは、以下のように記述し、パターンにマッチした式を評価します。

Scala
対象 match { case パターン => 式 ... }

以下の例では、Person.nameの値によって"太郎"、"花子"、Person.nameを返す関数を定義しています。

def getJapaneseName(person: Person): String = { person.name match { case "Taro" => "太郎" case "Hanako" => "花子" case name => name } }

では、定義した関数を呼び出してみます。

以下の場合、Person.nameが、"Taro"のため、matchの戻り値は、"太郎"となります。

println(getJapaneseName(Person(20, "Taro")))

実行結果は、以下のようになります。

太郎

以下の場合、Person.nameが、"Hanako"のため、matchの戻り値は、"花子"となります。

println(getJapaneseName(Person(19, "Hanako")))

実行結果は、以下のようになります。

花子

上記例は、単純なパターンマッチの例ですが、Scalaのmatchは、それ以外に型によるパターンマッチや、パターンマッチによる値の取り出し等、便利な使い方があります。
詳細は、matchの説明の記事を参照してください。

whileの戻り値

whileは、以下のように記述します。

Scala
while(条件式) 式

whileは、条件式がtrueの間、式を評価します。
条件式がfalseになったら、評価を中止します。
whileも式なのですが、返すべき値がないため、whileの値は、Unitです。

以下の例では、1から9の数値を加算した値を求めています。
「変数 x」の値は、1から9までの数値を加算した54ですが、「変数 y」の値は、Unitです。

var x = 0 var i = 1 val y = while(i < 10) { i = i + 1 x = x + i } println(s"x=${x}") println(s"y=${y}")

実行結果は、以下のようになります。

x=54 y=()

do-whileの戻り値

Scala 3ではdo-whileはサポートされませんので、新規に利用するのは控えましょう。

Scala 3でもScalaのコンパイラオプションに-language:Scala2Compatを指定すると、do-whileを使用することができます。
さらに、-rewriteを指定すると、コンパイラが自動的に該当箇所を書き換えてくれます。ぜひ活用しましょう。

以下ではScala 2系に関して説明します。

さて、Scala 2系にはJavaとの互換性のため、do-whileが用意されていました。

do-whilewhileと同じような動作をします。
whileと違うところは、式を評価してから条件式を評価するため、最低1回は式を評価することです。
do-whileは、以下のように記述します。

Scala
do 式 while(条件式)

以下の例では、条件式にfalseを指定していますが、式を評価してから、条件式を評価するため、「変数 x」は4となります。
「変数 y」の値は、whileと同じUnitです。

var x = 2 val y = do { x = x * 2 } while(false) println(s"x=${x}") println(s"y=${y}")

実行結果は、以下のようになります。

x=4 y=()

サイト内検索