Scala の基本文法
[最終更新] (2019/06/03 00:40:32)
最近の投稿
注目の記事

概要

Scala は JVM 上で動作するバイトコードにコンパイルできる言語です。JAVA よりも柔軟な記述ができます。事前にこちらからダウンロードおよびインストールしておいてください。基本的な文法をまとめます。

変数および定数

詳細は『Scala の型に関する知識』をご参照ください。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val constVal = 1 // 定数
    var variableVal = 1 // 変数

    val intVal: Int = 1 // 型指定定数
    var intVar: Int = 1 // 型指定変数

    // 基本的な型
    val longVal = 1L
    val floatVal = 1.0f
    val doubleVal = 1.0
    val charVal = 'a'
    val stringVal = "string"
    val nullVal = null

    // Any 型 (Scala の全ての親クラス)
    // 関連情報: https://www.qoosky.io/techs/3fef7fa668
    val a: Any = 1
    a.asInstanceOf[Int] // キャスト
  }
}

条件分岐

詳細は『Scala 組み込みの制御構造』をご参照ください。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    if (true) {
      println("true")
    }
    else {
      println("false")
    }
    val myval = if (true) 1 else 0
  }
}

ループ処理

詳細は『Scala 組み込みの制御構造』をご参照ください。

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

ブロックおよび関数

詳細は『Scala 関数のサンプルコード』をご参照ください。

ブロック

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val result = {
      val a = 1
      val b = 2
      a + b
    }
    println(result) //=> 3
  }
}

関数

object HelloWorld {
  def main(args: Array[String]): Unit = {
    def myFunc1(a: Int, b: Int): Int = {
      return a + b
    }
    def myFunc2(a: Int, b: Int): Int = {
      a + b
    }
    def myFunc3(a: Int, b: Int) = {
      a + b
    }
    def myFunc4(a: Int, b: Int) = a + b
    def myFunc5 = 3
    println(myFunc1(1,2)) //=> 3
    println(myFunc2(1,2)) //=> 3
    println(myFunc3(1,2)) //=> 3
    println(myFunc4(1,2)) //=> 3
    println(myFunc5) //=> 3
  }
}

クラス定義

引数なしコンストラクタ

object HelloWorld {
  def main(args: Array[String]): Unit = {
    class MyClass {
      val prop = 1
      def method(arg: Int) = prop + arg
    }
    val obj = new MyClass
    println(obj.method(2)) //=> 3
  }
}

引数ありコンストラクタ

object HelloWorld {
  def main(args: Array[String]): Unit = {
    class MyClass(_arg: Int) {
      val prop = _arg
      def method(arg: Int) = prop + arg
    }
    val obj = new MyClass(1)
    println(obj.method(2)) //=> 3
  }
}

コンストラクタに記載した処理はインスタンスを生成したタイミングで実行されます。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    class MyClass {
      println(123)
    }
    val obj = new MyClass //=> 123
  }
}

継承

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

    // 親クラス
    class MyClass {
      val prop1 = 123
      var prop2 = "abc"
      def method: Unit = println("MyClass")
    }

    // インスタンス化
    val obj = new MyClass
    println(obj.prop1) //=> 123
    obj.prop2 = "xyz" // 'var' にはセッターがある
    println(obj.prop2) //=> xyz

    // 子クラス
    class MySubClass extends MyClass {
      override val prop1 = 456 // val には 'override' が必要
      prop2 = "xyz" // var には 'override' は不要 (というよりは「上書きする」)
      override def method: Unit = { //メソッドのオーバーライド
        super.method // 親クラスは super で参照
        println("MySubClass")
      }
      final val prop3: String = "final でオーバーライドできなくする。"
    }
    val obj2 = new MySubClass
    obj2.method //=> MyClass\nMySubClass
    println(obj2.prop1) //=> 456
    println(obj2.prop2) //=> xyz
    println(obj2.prop3) //=> final でオーバーライドできなくする。
  }
}

抽象クラス

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

    abstract class MyAbstractClass {
      val prop: String
      def method(arg: Int): Int
    }
    class MyConcreteClass extends MyAbstractClass {
      val prop: String = "abc"
      def method(arg: Int): Int = {
        arg + 1
      }
    }
    val obj = new MyConcreteClass
    println(obj.prop) //=> abc
    println(obj.method(1)) //=> 2
  }
}

インスタンスは何のクラスであるか

クラスオブジェクトを比較して検証できます。isInstanceOf を利用したほうがスマートです。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val i = 123
    println(classOf[Int]) //=> int
    println(i.getClass == classOf[Int]) //=> true
  }
}

無名クラス

import scala.language.reflectiveCalls

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val obj = new {
      val prop = 123
    }
    println(obj.prop) //=> 123
  }
}

シングルトン

Singletonパターンの実装例 (Java)』は Scala では Object で実現できます。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    object Singleton {
      val prop = 123
    }
    println(Singleton.prop) //=> 123
  }
}

シノニム typedef (C++) のようなもの

object HelloWorld {
  def main(args: Array[String]): Unit = {
    type MyType[A] = List[List[A]]
    val obj: MyType[Int] = List(List(1), List(2))
    println(obj) //=> List(List(1), List(2))
    type Three[A] = Tuple3[A, A, A]
    type M[A, B] = scala.collection.mutable.Map[A, B]
  }
}

ジェネリッククラス

C++ クラステンプレート のように型を既定しないクラスを実装できます。

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

    class MyClass[A] {
      var list: List[A] = Nil
    }

    val obj = new MyClass[Int]

    obj.list = 1 :: obj.list
    obj.list = 2 :: obj.list
    println(obj.list) //=> List(2, 1)
  }
}

配列

詳細は『Scala コレクション』をご参照ください。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val intArr = new Array[Int](10)
    for(elem <- intArr) {
      println(elem)
    }
  }
}

配列バッファー

可変長の配列です。リストと異なり配列ですのでインデックスで指定した要素へのアクセスは高速ですが、要素の追加や削除の処理は現在のサイズ分のメモリ領域を新しく確保しなおす必要があるため低速です。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    import scala.collection.mutable.ArrayBuffer
    val buf = new ArrayBuffer[Int]()
    buf += 1
    buf += 2
    3 +=: buf
    println(buf) //=> ArrayBuffer(3, 1, 2)
  }
}

リスト

詳細は『Scala コレクション』をご参照ください。

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

    // これは配列
    val intArr = new Array[Int](2)
    intArr(0) = 10
    intArr(1) = 20
    println(intArr(0)) //=> 10
    println(intArr(1)) //=> 20

    // 以下はリスト

    // Nil と空リストは等しい
    println(List() == Nil) //=> true

    // リストを結合で生成
    val list = 1 :: 2 :: List(3,4) ::: List(5,6)
    println(list) //=> List(1, 2, 3, 4, 5, 6)
    println(list(0)) //=> 1
    println(1 :: 2 :: Nil) //=> List(1, 2) 空のリスト Nil の先頭に要素を追加

    val newList1 = list :+ 1 // 末尾に追加
    val newList2 = 1 +: list // 先頭に追加
    println(newList1 ++ newList2) // 連結 (リストの場合は ::: でもよい)
    println(list ++ intArr) // 左辺の型 List になる
    println(list ++: intArr) // 右辺の型 Array になる

    // カウント
    println(list.count(s => s < 6)) //=> 5
    println(list.count{ _ < 6 }) //=> 5

    // 存在確認
    println(list.exists{ _ == 1 }) //=> true
    println(list.contains(0)) //=> false

    // すべてが〜である、かどうか
    println(list.forall{ _ > 0 }) //=> true

    // 先頭の要素、最後の要素
    println(list.head) //=> 1 (空のリストでは例外)
    println(list.last) //=> 6 (空のリストでは例外)
    println(Nil.headOption) //=> None
    println(Nil.lastOption) //=> None

    // 先頭を除いたリスト、最後を除いたリスト
    println(list.tail) //=> List(2, 3, 4, 5, 6)
    println(list.init) //=> List(1, 2, 3, 4, 5)

    // 先頭から N 個取得または破棄
    println(List(1,2,3,4,5).take(2)) // 先頭から二つ List(1, 2)
    println(List(1,2,3,4,5).drop(2)) // 先頭から二つを除いたもの List(3, 4, 5)
    println(List(1,2,3,4,5).takeWhile{ _ < 4 }) //=> List(1, 2, 3)
    println(List(1,2,3,4,5).dropWhile{ _ < 4 }) //=> List(4, 5)

    // 一定範囲のみを取得
    println(List("a", "b", "c", "d", "e").slice(2, 4)) // slice(i,j) = List(Ei, Ei+1,..., Ej-1)
    //=> List(c, d)

    // 空であるかどうか (一つだけ見ればよいため size == 0 より高速)
    println(list.isEmpty) //=> false
    println(list.nonEmpty) //=> true

    // リストの長さ
    println(list.length) //=> 6
    println(list.size) //=> 6

    // マップ
    println(list.map{ _ * 2 }) //=> List(2, 4, 6, 8, 10, 12)

    // 文字列の生成 (Join のようなもの)
    println(list.mkString(", ")) //=> 1, 2, 3, 4, 5, 6

    // 逆転
    println(list.reverse) //=> List(6, 5, 4, 3, 2, 1)

    // 要素の削除 (フィルタリングして除外して新たなリストを作成)
    println(list.filter{ _ == 1 }) //=> List(1)
    println(list.filterNot{ _ > 2 }) //=> List(1, 2)

    // ソート
    println(list.sortWith((s,t) => s < t)) // sort
    //=> List(1, 2, 3, 4, 5, 6)

    // map でチェーンする場合に高速化
    // (中間 List を生成せずに map も適用しながら filter するため withFilter が高速)
    val result = list.filter { _ != 1 } map { _.toString }
    val result2 = list.withFilter { _ != 1 } map { _.toString }
    println(result) //=> List(2, 3, 4, 5, 6)
    println(result2) //=> List(2, 3, 4, 5, 6)
  }
}

リストバッファー

リストはその性質上、末尾へのアクセスが遅くなります。末尾への要素の追加が頻繁に発生して速度が気になる場合はリストバッファーを使用します。

object HelloWorld {
  def main(args: Array[String]): Unit = {
    import scala.collection.mutable.ListBuffer
    val buf = new ListBuffer[Int]
    buf += 10
    buf += 20
    30 +=: buf
    println(buf) //=> ListBuffer(30, 10, 20)

    val list = buf.toList
    println(list) //=> List(30, 10, 20)
  }
}

タプル

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

    // タプルには異なる型が格納できる
    val pair: Tuple2[Int, String] = (99, "This is a string.")
    println(pair._1 + 1) //=> 100
    println(pair._2 + 1) //=> This is a string.1

    // 例えば、リストではできない (Any になる)
    // [参考] Scala の型に関する知識 https://www.qoosky.io/techs/297
    val list: List[Any] = List(99, "This is a string.")
    println(list.head.asInstanceOf[Int] + 1) // Any からキャストする必要がある
    println(list.last.asInstanceOf[String] + 1) // Any からキャストする必要がある

    // 型を明記する例
    val tuple:(Int,Int) = (1, 2)

    // 値の取得
    val (intValA, intValB) = tuple
    println(intValA) //=> 1
    println(intValB) //=> 2
    println(tuple._1) //=> 1
    println(tuple._2) //=> 2
    tuple match {
      case(intValC, intValD) => {
        println(intValC) //=> 1
        println(intValD) //=> 2
      }
    }
  }
}

集合と連想配列

詳細は『Scala コレクション』をご参照ください。

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

    // 集合
    import scala.collection.mutable.Set
    val mySet = Set("A", "B")
    mySet += "C"
    println(mySet.contains("C")) //=> true

    // 連想配列
    import scala.collection.mutable.Map
    val myMap = Map[String, Int]()
    myMap += ("A" -> 1)
    myMap += ("B" -> 2)
    println(myMap("B")) //=> 2

    val myMap2 = Map(
      "a" -> 10,
      "b" -> 20
    )
    println(myMap2) //=> Map(b -> 20, a -> 10)
  }
}

Java で null 判定していた箇所には Option 型を活用

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

    // 連想配列
    val myMap = Map(
      "a" -> 10,
      "b" -> 20
    )

    // キーが存在する場合
    println(myMap("a")) //=> 10
    println(myMap.get("a")) //=> Some(10)
    println(myMap get "a") //=> Some(10)

    // キーが存在しない場合
    // println(myMap("c")) //=> java.util.NoSuchElementException
    println(myMap.get("c")) //=> None

    // Option 型はパターンマッチで条件分岐
    // ( Scala の Option[T] は null と比較しても意味がないため
    //   Java のように if-else で null 判定してはならない )
    def show(x: Option[Int]) = x match {
      case Some(i) => i
      case None => null
    }
    println(show(myMap get "a")) //=> 10
    println(show(myMap get "c")) //=> null

    // Option 型は Some で囲えば作れる
    println(Some(1)) //=> Some(1)
    println(None) //=> None
  }
}

Option 型の便利なメソッド

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val option: Option[Int] = Some(123)
    val option2: Option[Int] = null
    val option3: Option[Int] = None

    // Map の get と区別。Option 型の get
    println(option.get)
    // println(option2.get) // java.lang.NullPointerException
    // println(option3.get) // java.util.NoSuchElementException: None.get

    // 以下 null はすべて例外を投げるため除外:

    // 定義済みかどうかを判定
    println(option.isEmpty) //=> false
    println(option.isDefined) //=> true
    println(option3.isEmpty) //=> true
    println(option3.isDefined) //=> false

    // None の場合に null または指定した値を返す
    println(option.orNull) //=> 123
    println(option.getOrElse(-1)) //=> 123
    println(option3.orNull) //=> null
    println(option3.getOrElse(-1)) //=> -1

    // None の場合は処理しない
    option.foreach{ value: Int =>
      println(value) //=> 123
    }
    option3.foreach{ value: Int =>
      println(value) // None のため実行されない
    }
  }
}

ファイルの読み込み

詳細は『Scala ファイル関連の処理』をご参照ください。

import scala.io.Source

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

    if(args.length > 0) {
      for(line <- Source.fromFile(args(0)).getLines())
        println(line.length + " " + line)
    }
    else
      Console.err.println("Please enter filename")
  }
}

正規表現

この続きが気になる方は
関連ページ
    ファイル操作 (作成、移動、削除、探索) java.nio.file._ と java.io.File を利用しています。 import java.nio.file.{Paths, Files} import java.nio.file.StandardCopyOption.REPLACE_EXISTING import java.io.{File => JFile} // リネームして区別しや
    インストール 2016-2-9 現在のところ Scala で YAML を扱うこなれた方法はないようです。ここでは SnakeYAML を利用します。 build.sbt (sbt) libraryDependencies += "org.yaml" % "snakeyaml" % "1.16" pom.xml (maven)
    基本型と参照型 Java のデータ型は基本型と参照型に分類されます。基本型には null は代入できません。基本型には null 以外の初期値があり、boolean は false、int や long は 0 です。 class Main { public static void main(String args[]) { // 基本型 boolean
    概要 Lombok というライブラリを導入すると、Getter/Setter といったよく記述するコードをアノテーションだけで自動生成できます。Google Guava と同様に、Java の冗長なコードを削減する効果があります。簡単な使い方をまとめます。 インストール こちらのページの情報をもとにインストールします。
    相互変換 object Main { def main(args: Array[String]): Unit = { // 順序のあるコレクション // Traversable -> Iterable -> Seq // -> List // -> Array // -> Buffer -> ListBuffer, ArrayBuffer
    概要 Go 言語に関する基本的な事項を記載します。 モジュール、パッケージ、ライブラリ、アプリケーション 一つ以上の関数をまとめたものをパッケージとして利用します。更に一つ以上のパッケージをまとめたものをモジュールとして利用します。モジュールにはライブラリとして機能するものと、アプリケーションとして機能するものがあります。