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

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

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

工作HardwareHub ロゴ画像 (Laptop端末利用時)
工作HardwareHub ロゴ画像 (Mobile端末利用時)

Scala の基本文法

モーダルを閉じる

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

モーダルを閉じる

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

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

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

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

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

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

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

目次

    アカウント プロフィール画像 (サイドバー)

    Scalaはいいぞ

    0
    ステッカーを贈るとは?

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

    便利なリンク集

    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 ...
        したくんしたくん6/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...
        したくんしたくん6/5/2018に更新
        いいねアイコン画像0
      • 酢豚の基本的な使い方 (sbt)
        sbt は Scala および Java を主な対象としたビルドツールです。Scala Build Tool の略ではありませんが、Simple Build Tool という明示的な記述も公式ドキュメントなどには見当りません。以下 sbt の基本的な使用例をまとめます。使用した sbt のバージョンは 0.13 です。 公式ドキュメント [sbt 0.13](http://www.scala-sb...
        ねこねこ6/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...
        したくんしたくん6/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) } ...
        したくんしたくん10/7/2021に更新
        いいねアイコン画像0