Web上でサクッと試したい場合はScalaFiddleをば。
基本のき
コメント
// 一行コメント
/*
複数行コメント
複数行コメント
*/
文字出力
// 改行なし
print("出力したい内容")
// 改行あり
println("出力したい内容")
変数/定数
// 変数
var x: Int = 1
// 定数
val y: Int = 1
値の型は推論されるため省略可能。
// 型宣言である「: Int」の部分は値から推論されるため省略可能
val x = 1
四則演算
他のプログラミング言語と同様に+
,-
,*
,/
,%
が利用可能。
println(1 + 1) // 2
println(3 - 1) // 2
println(4 * 2) // 8
println(10 / 2) // 5
println(10 % 3) // 1
ブロック
{}
を用いて処理をまとめることができる。
最終行が結果として評価される。なお、Scalaにもreturn
は存在するが滅多に使わないらしい。
println({
val x = 5
val y = 2
val z = 3
val a = x + y
a % z
}) // 1
制御文
条件分岐
if文
val age = 21
if (age < 20) {
println("未成年")
} else {
println("成人")
} // 成人
一行の場合、{}
は省略可能。
if (age < 20) println("未成年")
else println("成人")
なお、Scalaに三項演算子はないがif-else
を用いて、それっぽく表現できる。
val x = 3
val ans = if (x % 2 == 0) "even" else "odd"
println(ans) // ans
match
他のプログラミング言語のswitch
のようなもの。同じではない。
val lang = "EN"
val x = lang match {
case "EN" => "ABCDE"
case "JP" => "あいうえお"
case _ => "other"
}
println(x) // ABCDE
色々特有の面白さがありそうだがややこいのでここでは省略。
繰り返し
繰り返しに関しては制御文より、Seqなどのコレクションタイプのメソッドを利用することが多い印象。正直あんまり使わないのでは。
while文
var i = 1
while(i <= 10) {
println(i)
i += 1
}
// 1
// 2
// 3
// 4
// 5
for文
for(x <- 1 to 5){
println(x)
}
// 1
// 2
// 3
// 4
// 5
関数とメソッド
関数とメソッドの違いはよくわかってない。
関数
パラメータを受け取り、評価する式のこと。(パラメータ: パラメータの型) => 式
と書く。
下記の例は受け取った値を2倍にする無名関数。
(x: Int) => x * 2
関数には名前を付与して宣言することも可能。
val 名前 = (パラメータ: パラメータの型) => 式
と書く。
val double = (x: Int) => x * 2
println(double(3)) // 6
println(double(5)) // 10
パラメータを複数設定することや、パラメータなしにすることも可能。
val sum = (x: Int, y: Int) => x + y
println(sum(1, 2)) // 3
println(sum(5, 6)) // 11
val pi = () => 3.14
println(pi()) // 3.14
メソッド
def
を用いて宣言をし、def 名前(パラメータ: パラメータの型): 戻り値の型 => 処理
と書く。
def sum(x: Int, y: Int): Int = x + y
println(sum(1,2))
メソッドは複数のパラメータリストを受け取ることができる。
def addThenMultiply(x: Int, y: Int)(z: Int): Int = (x + y) * z
println(addThenMultiply(1, 2)(3)) // 9
複数行の処理がある場合、最終行の結果が戻り値となる。
def addThenMultiply(x: Int, y: Int)(z: Int): Int = {
val sum = x + y
sum * z
}
println(addThenMultiply(1, 2)(3)) // 9
クラス
クラス
class
を用いてクラスを定義。class クラス名 {}
と書く。
new クラス名()
でインスタンスを生成
class Person {
def greet(): Unit = println("Hi!")
}
val p = new Person()
p.greet() // Hi!
クラス名の後ろにコンストラクタパラメータを続けることでメンバを定義できる。
class Person(name: String) {
def greet(): Unit = println("Hi! I'm " + name + ".")
}
val p = new Person("rokumura")
p.greet() // Hi! I'm rokumura.
ケースクラス
ケースクラスは不変であり、値で比較される。
上述の通常のクラスはインスタンス同士の比較となる。
なお、ケースクラスはnew
なしでインスタンス化できる。
// 通常のクラス
class Person(name: String) {}
val p1 = new Person("rokumura")
val p2 = new Person("rokumura")
if (p1 == p2) println("p1とp2は同じ")
else println("p1とp2は異なる")
// 値は同じだがインスタンスが異なるため「p1とp2は異なる」と判定される
// ケースクラス
case class CasePerson(name: String) {}
val c1 = CasePerson("rokumura")
val c2 = CasePerson("rokumura")
if (c1 == c2) println("p1とp2は同じ")
else println("p1とp2は異なる")
// インスタンスが異なるが値が同じであるため「p1とp2は同じ」と判定される
オブジェクト
オブジェクトは単一のインスタンスであり、シングルトンと考えることができる。
object 名前 {}
と書く。
object Counter {
private var num = 0
def add(): Unit = num += 1
def getNum(): Int = num
}
println(Counter.getNum()) // 0
Counter.add()
println(Counter.getNum()) // 1
Counter.add()
Counter.add()
println(Counter.getNum()) // 3
トレイト
フィールドとメソッドを持つ型。trait 名前 {}
と書く。
振る舞いだけを宣言することも、実装を持つこともできる。
振る舞いのみを定義した場合、継承するクラス(継承にはextends
を用いる)は振る舞いの実装を強制される。
また、複数のtrait
を継承することも可能。(class クラス名 extends トレイトA with トレイトB
と書く)
trait Engineer {
def develop(): Unit
}
class BackendEngineer extends Engineer {
override def develop(): Unit = println("バックエンドを開発します")
}
class FrontendEngineer extends Engineer {
override def develop(): Unit = println("フロントエンドを開発します")
}
val bEngineer = new BackendEngineer()
bEngineer.develop() // バックエンドを開発します
val fEngineer = new FrontendEngineer()
fEngineer.develop() // フロントエンドを開発します
同じトレイトを継承しているものは、抽象化した状態で扱うことができる。
val engineers: Seq[Engineer] = Seq(
new BackendEngineer(),
new FrontendEngineer()
) // Engineerの集合として扱い、それぞれがBackendかFrontendかは意識していない。
// 集合の各要素によって結果が変わる
engineers.foreach(e => e.develop())
// バックエンドを開発します
// フロントエンドを開発します
参考
ぶっちゃけ下記リンクを一読したほうが良い🍣