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 文字列の処理書式指定 object Main { def main(args: Array[String]): Unit = { println("%d + %d = %d".format(1, 1, 2)) //=> 1 + 1 = 2 } } 文字列の比較 ヒアドキュメント 他の言語でいう「ヒアドキュメント」のようなものは """ で囲うことで実現できます。 object Main ...
- Scala 日付に関する処理Date クラスを文字列にフォーマット import java.util.Date object Main { def main(args: Array[String]): Unit = { // format は Date に限らない文字列用の機能です。 println("%d-%d-%d" format (1, 1, 1)) //=> 1-1-1 printl...
- 酢豚の基本的な使い方 (sbt)sbt は Scala および Java を主な対象としたビルドツールです。Scala Build Tool の略ではありませんが、Simple Build Tool という明示的な記述も公式ドキュメントなどには見当りません。以下 sbt の基本的な使用例をまとめます。使用した sbt のバージョンは 0.13 です。 公式ドキュメント [sbt 0.13](http://www.scala-sb...
- Scala 関数のサンプルコード「デフォルト引数」および「Unit 型を返す関数」 object HelloWorld { def main(args: Array[String]): Unit = { def myPrint(myArg: String = "default_value") = println(myArg + "!") val result = myPrint() //=> defau...
- Scala の基本文法Scala は JVM 上で動作するバイトコードにコンパイルできる言語です。JAVA よりも柔軟な記述ができます。事前にこちらからダウンロードおよびインストールしておいてください。基本的な文法をまとめます。 変数および定数 object HelloWorld { def main(args: Array[String]): Unit = { val constVal = 1 //