Scala 組み込みの制御構造
[履歴] [最終更新] (2016/02/14 23:40:01)
1
作品
364
技術情報
最近の投稿
ここは
趣味の電子工作を楽しむ人のためのハードウェア情報共有サイト

技術情報や作品の投稿機能、リアルタイム遠隔操作 API をご利用いただけます。
新着作品

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
  }
}

型でマッチ

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val myVal: Any = List(1,2,3)
    myVal match {
      case x: Int => {
      }
      case x: String => {
      }
      case x: List[_] => {
        println(x) //=> List(1, 2, 3)
      }
      case _ => {
      }
    }
  }
}

case class

object HelloWorld {
  def main(args: Array[String]): Unit = {
    case class MyCaseClass(prop1: Int, prop2: String)
    val obj = new MyCaseClass(0, "ABC")
    obj match { //=> prop1: 0, prop2: ABC
      case MyCaseClass(1, _) => {
      }
      case MyCaseClass(_, "abc") => {
      }
      case MyCaseClass(prop1, prop2) => { // 変数バインド
        println("prop1: %d, prop2: %s" format (prop1, prop2))
      }
    }

    case class MyCaseSuperClass(prop1: Int, prop2: MyCaseClass)
    val obj2 = new MyCaseSuperClass(123, obj)
    obj2 match { //=> MyCaseClass(0,ABC)
      case MyCaseSuperClass(prop1, MyCaseClass(_, "abc")) => {
      }
      case MyCaseSuperClass(prop1, matchedObj @ MyCaseClass(_, _)) => { // '@' で case class ごとバインド
        println(matchedObj)
      }
      case _ => {
      }
    }
  }
}

break-continue

scala には break-continue がありません。再帰関数などで処理を実現することが推奨されています。どうしても必要だと感じた場合には標準ライブラリをインポートすることで break は使用できるようになります。

import scala.util.control.Breaks._
import java.io._

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val in = new BufferedReader(new InputStreamReader(System.in))
    breakable {
      while(true) {
        val line = in.readLine()
        println(line)
        if(line == "") break
      }
    }
  }
}

break で例外が投げられて breakable でキャッチする作りになっていることを利用した (バッド) ノウハウを用いれば continue も実現できます。

import scala.util.control.Breaks.{break => continue, breakable => continuable}

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