モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

Scala の基本文法

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2015/03/22
最終更新最終更新
2021/09/07
記事区分記事区分
一般公開

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

変数および定数

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 の全ての親クラス)
    val a: Any = 1
    a.asInstanceOf[Int] // キャスト
  }
}

条件分岐

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

ループ処理

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

ブロックおよび関数

ブロック

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パターンは 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)
  }
}

配列

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

リスト

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 になる)
    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
      }
    }
  }
}

集合と連想配列

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 のため実行されない
    }
  }
}

ファイルの読み込み

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

正規表現

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

    println("string".matches("""\w{6}""")) //=> true

    val pattern = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
    val res = "9999-12-31" match {
      case pattern(year, month, day) => year + "/" + month + "/" + day
      case _ => false
    }
    println(res) //=> 9999/12/31
  }
}

コンソール出力

object HelloWorld {
  def main(args: Array[String]) : Unit = {
    print("print\n") // 改行なし
    println("println") // 改行あり
    printf("%d / %d = %f\n", 1, 2, 1/2.0) // 書式指定
    println("%d / %d = %f".format(1, 2, 1/2.0)) // 書式指定
  }
}

コンソール入力

import scala.io.StdIn._

object HelloWorld {
  def main(args: Array[String]) : Unit = {
    // 書式指定, 有限個 readfN (N=1,2,3)
    val (year: String, month: String, day: String) = readf3("{0}/{1}/{2}") // タプルを返す
    println("year: %s".format(year))
    println("month: %s".format(month))
    println("day: %s".format(day))

    // 書式指定, 無限個 readfN (N=1,2,3)
    val list: List[Any] = readf("{0}/{1}/{2}")
    println("year: %s".format(list(0)))
    println("month: %s".format(list(1)))
    println("day: %s".format(list(2)))

    // 一行そのまま
    val line = readLine("line: ")
    println(line)

    // 型を指定して検証
    print("int: ")
    val myInt = readInt // readDouble, readLong, readBoolean 等もあります
    println(myInt)
    assert(myInt > 0, "%d は 0 以下です。".format(myInt))
  }
}

遅延評価

lazy を指定すると、最初に参照されたタイミングで式が評価されるようになります。アプリケーションの起動速度の改善などにつながります。

object HelloWorld {
  def main(args: Array[String]) : Unit = {
    var i = 0;
    lazy val a = i * 2; // ここでは式が評価されない
    val b = i * 2;

    i = 1;
    println(a) //=> 2 ←ここで式 i*2 が評価される
    println(b) //=> 0

    i = 2;
    println(a) //=> 2 // 再評価はされない
  }
}

外部コマンドの実行

import scala.sys.process._
import scala.language.postfixOps

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

    val cmd = "ls"
    val code: Int = cmd ! // 終了ステータス ('!' の後には空行が必要)

    println(code) //=> 0

    val res: String = cmd !! // 結果文字列 ('!!' の後にも空行が必要)

    println(res)
  }
}

アクセサをクラスに追加

JavaBeans 形式のアクセサ (ゲッターとセッター) をクラスに追加できます。

import scala.beans.BeanProperty

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

    case class MyClass(
      @BeanProperty var prop1: Int,
      @BeanProperty var prop2: String)

    val obj = new MyClass(123, "abc")
    obj.setProp2("xyz")

    println(obj.getProp1) //=> 123
    println(obj.getProp2) //=> xyz
  }
}

Java の資産を利用

Scala からは Java のパッケージがそのまま利用できます。例えば Java の Random や Date を利用するには以下のようにします。

import java.util.Random
import java.util.Date
// import java.util._ // としてもよいです
// import java.util.* // ではないことに注意

object HelloWorld {
  def main(args: Array[String]): Unit = {
    val generator = new Random()
    println(generator.nextInt())

    val now = new Date()
    println(now)
  }
}

便利なリンク集

Likeボタン(off)0
詳細設定を開く/閉じる
アカウント プロフィール画像

Scalaはいいぞ

記事の執筆者にステッカーを贈る

有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

>>さらに詳しくステッカーを贈る
ステッカーを贈る コンセプト画像

Feedbacks

Feedbacks コンセプト画像

    ログインするとコメントを投稿できます。

    ログインする

    関連記事

    • Scala 文字列の処理
      書式指定 object Main { def main(args: Array[String]): Unit = { println("%d + %d = %d".format(1, 1, 2)) //=> 1 + 1 = 2 } } 文字列の比較 ヒアドキュメント 他の言語でいう「ヒアドキュメント」のようなものは """ で囲うことで実現できます。 object Main ...
      したくんしたくん5/18/2018に更新
      いいねアイコン画像0
    • 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...
      したくんしたくん5/5/2018に更新
      いいねアイコン画像0
    • 酢豚の基本的な使い方 (sbt)
      sbt は Scala および Java を主な対象としたビルドツールです。Scala Build Tool の略ではありませんが、Simple Build Tool という明示的な記述も公式ドキュメントなどには見当りません。以下 sbt の基本的な使用例をまとめます。使用した sbt のバージョンは 0.13 です。 公式ドキュメント [sbt 0.13](http://www.scala-sb...
      ねこねこ5/30/2018に更新
      いいねアイコン画像0
    • Scala 関数のサンプルコード
      「デフォルト引数」および「Unit 型を返す関数」 object HelloWorld { def main(args: Array[String]): Unit = { def myPrint(myArg: String = "default_value") = println(myArg + "!") val result = myPrint() //=> defau...
      したくんしたくん5/26/2018に更新
      いいねアイコン画像0
    • Scala 組み込みの制御構造
      if-else 条件分岐で知られる if-else は三項演算子のようにも使用されます。 object HelloWorld { def main(args: Array[String]): Unit = { val myVal = if (!args.isEmpty) args(0) else "default" println(myVal) } ...
      したくんしたくん9/7/2021に更新
      いいねアイコン画像0