LoginSignup
56
62

More than 5 years have passed since last update.

Java職人がScalaやって覚えた基本を書いておく

Last updated at Posted at 2014-12-25

インストール

Windowsの場合、http://www.scala-lang.org/download/ からインストーラをダウンロードする。

Macの場合、brew install scala

※事前にJREのインストールが必要。

Scalaの特徴

  • オブジェクト指向と関数型言語の特徴を併せ持つ静的型付け言語。
  • JVM上で動作し、JavaのAPIやライブラリが使える。
  • Javaより簡潔に書ける。
  • Javaより強力な型推論。
  • スクリプトが書ける。
  • 演算子や制御構文を拡張できる。

Hello World

REPLでHello World

ScalaにはREPL(対話型インタープリター)が付属していて、コマンドラインから文を1行ずつ入力して実行する事ができる。
コマンドプロンプトからscalaコマンドを引数なしで実行するとREPLが起動する。

$ scala
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> println("Hello Scala")
Hello Scala

scala> :q
$ 

ScalaスクリプトでHello World

Scalaではスクリプトを作成する事ができる。
Scalaスクリプトファイルではクラスを定義せずにトップレベルから命令を書く。(クラスや関数を定義して使用する事も可能)

HelloScript.scala
println("Hello " + args(0))

実行はscalaコマンドの第1引数でスクリプトファイル名を指定する。第2引数以降はスクリプトに渡す引数になる。

$ scala HelloScript.scala Scalaスクリプト
Hello Scalaスクリプト
$ 

ScalaアプリケーションでHello World

アプリを作成するにはmainメソッドを持つシングルトンオブジェクトを作成する。

HelloApp.scala
object HelloApp {
  def main(args: Array[String]): Unit = {
    println("Hello " + args(0))
  }
}

Appトレイトを使用すると以下のように短く書けるようになる。

HelloApp.scala
object HelloApp extends App {
  println("Hello " + args(0))
}

実行はscalacコマンドでソースファイルをコンパイルしてからscalaコマンドで行う。

$ scalac HelloApp.scala && scala HelloApp Scalaアプリ
Hello Scalaアプリ
$ 

Scalaのソースファイルの基本

  • 拡張子は.scala
  • インデントはスペース2桁を推奨。
  • トップレベルに定義するクラス名はファイル名と同じでなくても良い。
  • トップレベルにpublicなクラスを複数定義できる。
  • 文末のセミコロンは省略できる。
  • アクセス修飾子を省略した時のデフォルトは公開。
  • Scalaでは以下のパッケージとオブジェクトのメンバーを暗黙でインポートする。

基本型

  • Byte
  • Short
  • Int
  • Long
  • Char
  • String
  • Float
  • Double
  • Boolean
  • Array

Javaではプリミティブ型とラッパークラスがあり、プリミティブ型はオブジェクトではないので特別な扱いが必要だったが、Scalaでは全てがオブジェクトとして扱える。

整数リテラルもIntクラスのオブジェクトなので以下のようにメソッドを呼び出す事もできる。

123.toString()

配列も特別な型ではなく、Javaのコレクションクラスのように型パラメータを持つArrayクラスのオブジェクトになる。

変数の定義

初期化後に再代入できない変数はval、再代入可能な変数にはvarを使用する。
型推論されるので型の指定は省略可能。

val a = 1
val b: Int = 2
// b = 2  //コンパイルエラー。val変数への再代入は不可。
var c = 3
var d: Int = 4
c = 5
d = 6
// c = "a"; //コンパイルエラー。型が違う値は再代入できない。

関数の定義

関数の定義はdefを使う。

class内またはobject内に定義した関数はメンバーメソッドになる。
スクリプトではクラスの外側でも関数を定義できる。

class Class1 {
  def method1() {} // クラスClass1のメンバーメソッド
}
def func1() {} // クラスとは独立した関数

戻り値を返す関数

2つの整数値を受け取って整数値を返す関数は以下のようになる。

def sum(a: Int, b: Int): Int = { return a + b }

returnを書かなくても最後の式が戻り値になる。

def sum(a: Int, b: Int): Int = { a + b }

式が1つの時は{}を省略できる。

def sum(a: Int, b: Int): Int = a + b

戻り値の型は型推論で省略できる。

def sum(a: Int, b: Int) = a + b

引数の型は省略できない。

戻り値がない関数

戻り値がない関数は戻り値の型をUnitにする。

def printText(text: String):Unit = println(text)

最後の式の結果がUnitなら戻り値の型を省略できる。

def printText(text: String) = println(text) //printlnの戻り値はUnitなのでこの関数の戻り値の型もUnitになる

関数本体の前に=を付けずに関数本体を{}で囲ってある場合は、最後の式が値を返してもこの関数の戻り値はUnitになる。

def func1(a: Int, b: Int) { sum(1, 2) } //戻り値はUnitになる

引数のデフォルト値

引数にデフォルト値を定義すると呼び出し時に省略可能になる。

def func1(a: Int = 0) = a + 1

println(func1(1)) // => 2
println(func1())  // => 1

関数リテラル

Java8でいうラムダ式。
関数を関数の引数に渡したり変数に代入する時に使用する。

val func1 = (a: Int, b: Int) => { a + b } : Int

戻り値の型を省略したり{}を省略できるのは関数定義と一緒。

val func1 = (a: Int, b: Int) => a + b

クラスの定義

クラスHogeに非公開フィールドaと公開メソッドgetAを定義するには以下のようにする。

class Hoge {
  private val a = 3
  def getA() = a
}

クラス本体の{}は省略できる。

class Hoge

基本コンストラクタ

クラスのブロック内に書いたコードが基本コンストラクタの処理になる。

class Hoge {
  println("created.")
}

new Hoge() // => created.

以下のように書くと、基本コンストラクタで引数を受け取ってクラスのフィールドに設定してくれる。

class Hoge(private val a: Int)

上記はJavaで以下のように書いたのと同じ意味。

public class Hoge {
    private int a;
    public Hoge(int a) {
        this.a = a;
    }
}

アクセス修飾子とvar/valを省略するとprivate valになる。

class Hoge(a: Int)

基本コンストラクタのアクセス修飾子はクラス名と引数の間に指定する。

class Hoge private (a: Int)

補助コンストラクタ

基本コンストラクタ以外にコンストラクタを定義する時はthisという名前のメソッドを使う。
補助コンストラクタでは最初に他のコンストラクタを呼ばなくてはならない。

class Hoge(a: Int) {
  def this(a: Int, b: Int) { this(a + b) }
}

親クラスのコンストラクタの呼び出し

class Parent(a: Int)
class Child extends Parent(1)
class Child(a: Int) extends Parent(a * 2)

override

親クラスのメソッドをオーバーライドする時はoverride修飾子をつける。(アノテーションではない)

class Hoge {
  def f() = println("hoge")
}
class Meke {
  override def f() = println("meke")
}

シングルトンオブジェクト

Javaではクラスに静的(static)メンバーを持つことができるが、Scalaではできない。
代わりにScalaではシングルトンオブジェクトを使用してそこにメンバーを定義する。

シングルトンオブジェクトの定義はobjectキーワードを使用する。

object Hoge {
  def method1() {}
}

使用する箇所ではJavaで静的メンバーを呼ぶのと同じ形式で呼び出す。

  Hoge.method1()

コンパニオンオブジェクト

クラスと同じ名前のシングルトンオブジェクトを定義した場合はコンパニオンオブジェクトと呼ばれる。
コンパニオンオブジェクトはクラスと同じソースファイルに定義しなければならない。

Hoge.scala
class Hoge {
}
object Hoge {
}

スタンドアロンオブジェクト

コンパニオンオブジェクトではないシングルトンオブジェクトは、スタンドアロンオブジェクトと呼ばれる。

パッケージ

Scalaでは1ファイルに複数パッケージを書いたり、ネストしたりできる。

Javaと同じ1ファイル1パッケージの書き方
import package1
class Class1
1ファイルに複数パッケージを書く
import package1 {
  class Class1
}
import package2 {
  import package3 {
    class Class2
    class Object3
  }
}

インポート

単一クラスのインポート
import package1.Class1
パッケージの全クラスのインポート
import package2.package3._
パッケージの指定クラスをインポート
import package2.package3.{Class2, Object3}
オブジェクトの全メンバーをインポート
import package2.package3.Object3._
パッケージのインポート
import package2.package3

new package3.Class2()

配列

サイズが3のInt配列を作成する。

val a = new Array[Int](3)

初期値を指定して配列を作成する。

val a = Array(1, 2, 3)

if式

Scalaのifは式なので値を返せる。

val a = if (b == 1) 1 else 2

ちょっと長くなったのでまとめ

だらだらと書いてたら長くなってしまったので終わりにする。

他にも以下は基本として覚えておかなければならないけど、またの機会にする。

  • trait
  • for式
  • コレクション

参考

書籍
Scalaスケーラブルプログラミング第2版

サイト
Scala公式サイト
Scalaメモ(Hishidama's Scala Memo)

56
62
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
56
62