Scala 組み込みの制御構造
[最終更新] (2019/06/03 00:44:23)
最近の投稿
注目の記事

if-else

条件分岐で知られる if-else は三項演算子のようにも使用されます。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val myVal =
      if (!args.isEmpty) args(0)
      else "default"
    println(myVal)
  }
}

実行例

$ scala sample.scala
default

while は非推奨

scala において while は極力使用せずに別の手段で代用できないか考えるとよいとされます。例えば他の言語でよく用いられる

var tmp = null
while((tmp = myFunc()) != null)
  println(tmp)

といった形式のコードは動作しません。なぜならば scala において代入の結果は Unit 型の値となるからです。Unit 型の値とはすなわち () のことであり他の言語でいうところの void のようなものです。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    var tmp = ""
    println(tmp = "test") //=> ()
  }
}

while を使用するためにはどうしてもミュータブルな変数 var が必要になってしまい Scala らしいイミュータブルなコードになりません。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    var i = 0
    while(i < 2) {
      println(i)
      i = i + 1
    }
    do {
      println(i)
      i = i - 1
    } while(i > 0)
  }
}

foreach

object HelloWorld {
  def main(args: Array[String]): Unit = {
    args.foreach{arg =>
      // ループ風
      println(arg)
    }

    // 略記法
    args.foreach(println)
  }
}

for はとても優秀

List

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val list = List(1,2,3)
    for(e <- list) {
      println(e)
    }
  }
}

to, until

object HelloWorld {
  def main(args: Array[String]): Unit = {

    for(i <- 1 to 4) { // 1,2,3,4
      println(i)
    }

    for(i <- 1 until 4) { // 1,2,3
      println(i)
    }

    for(i <- 1 until (10, 3)) { // 1,4,7 (3つ飛ばし)
      println(i)
    }
    val range = Range(1, 10, 3) // こう書いても同じ
    for(i <- range) { // 1,4,7
      println(i)
    }
  }
}

コレクションの生成

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4)
    val list2 = for(e <- list if e % 2 == 0) yield e * 2
    println(list2) //=> List(4, 8)

    val list3 = for {
      i <- 1 to 10
      if i % 2 == 0
    } yield i
    println(list3) //=> Vector(2, 4, 6, 8, 10)
  }
}

if による抽出

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val files = (new java.io.File(".")).listFiles
    for(file <- files if file.getName.endsWith(".scala"))
      println(file)

    for(
      file <- files
      if file.isFile
      if file.getName.endsWith(".scala")
    ) println(file)
  }
}

for の中で for

for 文の入れ子をシンプルに記述できます。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    // (0,0), (0,1), (1,0), (1,1)
    for(i <- 0 to 1) {
      for(j <- 0 to 1) {
        println("i: %d, j: %d".format(i,j))
      }
    }

    for(i <- 0 to 1; j <- 0 to 1) {
      println("i: %d, j: %d".format(i,j))
    }

    for {
      i <- 0 to 1
      j <- 0 to 1 }{
      println("i: %d, j: %d".format(i,j))
    }
  }
}

少し複雑な例

object HelloWorld {
  def main(args: Array[String]): Unit = {
    grep(".*grep.*")
  }

  def grep(pattern: String): Unit = {
    for {
      file <- (new java.io.File(".")).listFiles
      if file.getName.endsWith(".scala")
      line <- scala.io.Source.fromFile(file).getLines().toList
      trimmed = line.trim
      if trimmed.matches(pattern)
    } println(file + ": " + trimmed)
}

ネストした List などの処理にも便利です。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val nestedList: List[List[String]] = List(
      List("A", "B"),
      List("a", "b")
    )
    for(l <- nestedList; e <- l if e == "a") println(e) //=> a
  }
}

match

他の言語の switch-case のようなものです。値を返すこともできます。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val myVal = "abc"
    myVal match { //=> 1
      case "abc" => println(1)
      case "def" => println(2)
      case _ => println(-1)
    }

    val myVal2 =
      myVal match {
        case "def" => "DEF"
        case _ => "default"
      }
    println(myVal2) //=> default
  }
}

変数へのバインド

_ の代わりに変数名を指定したバインドができます。その際の変数名は小文字から始まっている必要があります。大文字で始まる場合は定数とみなされて、値を比較されます。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val myVal = "abc"
    myVal match { //=> abc
      case "dummy" => {
      }
      case x => {
        println(x)
      }
    }

    val MyVal = "xyz"
    myVal match { //=> default
      case MyVal => {
      }
      case _ => {
        println("default")
      }
    }

    // 小文字開始の場合で、値を比較したい場合はバッククォートで囲みます。
    val myVal2 = "abc"
    myVal match { //=> myVal == myVal2
      case `myVal2` => {
        println("myVal == myVal2")
      }
      case _ => {
      }
    }
  }
}

文字列を正規表現でパターンマッチ

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val pattern = """(\d{4})/(\d{2})/(\d{2})""".r
    val str = "1999/12/31"
    str match { //=> str == 1999/12/31
      case pattern("1999", "12", "31") => {
        println("str == 1999/12/31")
      }
      case pattern(year, month, day) => {
      }
    }
  }
}

if で条件を指定 (パターンガード)

一致しなければいつも通り次の case の判定に移ります。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val myVal = "abc"
    myVal match { //=> abc
      case x if x == "abc" => {
        println(x)
      }
      case _ => {
      }
    }
  }
}

コレクションを用いたマッチ

object HelloWorld {
  def main(args: Array[String]): Unit = {
    // リスト
    val list = List(1, 2, 3)
    list match { //=> hi
      case List(1, 2, 3) => {
        println("hi")
      }
      case List(x, y, z) => { // バインド
      }
      case List(_, _) => { // 要素数が二つ
      }
      case List(0, _*) => { // 先頭の要素の値が 0 で、長さが任意のリスト
      }
      case _ => {
      }
    }

    // 配列も同様
    val arr = Array(1, 2, 3)
    arr match {
      case Array(1, 2, 3) => {
      }
      case _ => {
      }
    }

    // タプル
    val tuple = (0, 1)
    tuple match { //=> (0, 1)
      case (1, 2) => {
      }
      case (1, _) => {
      }
      case (x, y) => {
        println("(%d, %d)" format (x,y))
      }
    }
  }
}

再帰処理

object HelloWorld {
  def main(args: Array[String]): Unit = {
    def rec(list: List[Int]): Int = {
      list match {
        case x :: xs => {
          x * rec(xs) // 先頭の要素 :: 残りの要素からなるリスト
        }
        case Nil => {
          1
        }
      }
    }
    println(rec(List(1,2,3))) //=> 6
  }
}

型でマッチ

この続きが気になる方は

Scala 組み込みの制御構造

残り文字数は全体の約 22 %
tybot
100 円
関連ページ
    概要 sbt は Scala および Java を主な対象としたビルドツールです。Scala Build Tool の略ではありませんが、Simple Build Tool という明示的な記述も公式ドキュメントなどには見当りません。以下 sbt の基本的な使用例をまとめます。使用した sbt のバージョンは 0.13 です。
    概要 こちらに記載した Akka アクターを用いて実装された汎用 HTTP フレームワークです。Spray の後継です。コアモジュールである akka-http-core は 2016/2/17 に experimental が外れました。akka-http などのいくつかのサブモジュールは 2016/3/1 現在 experimental のままですが、基本的な機能に関しては大きな仕様変更はな
    概要 Akka 2.4.2 を用いたサンプルコード集です。動作には Java 8 以降が必要です。 Akka requires that you have Java 8 or later installed on your machine. インストール方法は複数提供されています。その一部を記載します。
    概要 Scala は JVM 上で動作するバイトコードにコンパイルできる言語です。JAVA よりも柔軟な記述ができます。事前にこちらからダウンロードおよびインストールしておいてください。基本的な文法をまとめます。 変数および定数 詳細は『Scala の型に関する知識』をご参照ください。 object HelloWorld { def main(args: Array[String]):