Scala をはじめよう 第2回目
今回はScalaの制御構文をまとめてみたい。
実行環境 (review)
前回構築したscala
orsbt
を用いる
REPL起動
# --- scala ---
$ scala
Welcome to Scala 2.13.3 (OpenJDK 64-Bit Server VM, Java 11.0.7).
Type in expressions for evaluation. Or try :help.
scala>
# --- sbt ---
$ sbt console
...
[info] Starting scala interpreter...
Welcome to Scala 2.12.10 (OpenJDK 64-Bit Server VM, Java 11.0.7).
Type in expressions for evaluation. Or try :help.
scala>
ソースファイルを作成して実行
拡張子は.scala
source.scala
object Main {
def main(args: Array[String]): Unit = {
println("scala program")
// 以下に処理を記述していく
}
}
- コンパイルして実行
$ scalac source.scala
$ scala Main
- コンパイルしないで実行
$ scala source.scala
sbt でコンパイル, 実行
何かフォルダを作っておくと良いと思います。
(名前はmyfolderとしましたが、なんでも良いです、対応する部分は読み替えてください)
$ mkdir myfolder
$ cd myfolder
myfolder下にソースファイルを書いて置きます。
source.scala
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, Scala World!")
// 以下に、処理を記載していく
}
}
myfolder下にsbt
の設定ファイルを置きます
build.sbt
scalaVersion := "2.12.10"
scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked", "-Xlint")
# フォルダたちの配置はこんな感じ
./myfolder (current working directory)
├── source.scala
└──build.sbt
sbt
を起動
[info] ...
sbt:myfolder>
run
コマンドで実行
sbt:myfolder> run
[info] Compiling 1 Scala source to ...
[info] Running source
Hello, Scala World!
[success] Total time: 1 s, completed 2015/02/09 15:44:44`
run
コマンドでは、mainメソッドを持つオブジェクトを探して実行してくれるらしい。
--- review ここまで ---
制御構文
「構文」、「式」、「文」について
- 「構文」: 予約語などを用いて、文法に従い、書いていったもの。
- 「式」: 評価(が成功)すると値になるもの。
- 「文」: 評価しても値にならないもの。
「構文の例」
- classやobjectの定義
source.scala
class ClassName {
...
}
object ObjectName {
def main(args: Array[String]): Unit = {
...
}
}
- 制御「構文」 (後述 - 本題)
「式の例」
// 計算や値
scala> 1 + 2
val res0: Int = 3 // <= 値になっている
scala> "Hello"
val res1: String = Hello // <= 値になっている
「文の例」
// 変数/定数の定義
var x: Int = 100
val a: double = 2.0
複数の式のまとまり
Scalaで、複数の「式」を{ }
でくくると、「くくったもの全体」を「大きな1つの式」と見なす。
並べられた複数の式は、
- 改行か、セミコロン
;
で区切られ - 上(前)から順に評価される。
- また、「最後の式を評価した値」が「全体の大きな1つの式」の返り値
となる。
例:
scala> { println("hoge"); println("piyo"); 3 + 5; }
hoge
piyo
val res0: Int = 8 // <= 最後の式を評価した値が返り値になる。
本題
if式
if (条件 /* なるべく肯定系で書く */ ) {
// 条件に合った時の処理
} else {
// 条件に合わなかった時の処理
}
- if文と同じく「条件に合致するかしないか」で分岐を行う。
- 分岐後の処理の部分には、その場合に落ちた時に評価される"式"を記述する。
-
else
の条件は省略可能- 省略した場合は
Unit型の ()
が返って来る。 - Unit型とは、いわゆる
Void型
に対応する型。雑にいうと「空っぽ」ってこと(だと思っている)。
- 省略した場合は
var age: Int = 17
if (age < 18) { // 18歳未満は未成年。
"未成年です。"
} else { // 18歳以上ならば成人済み
"成人です。"
}
// ちなみに、評価すると、「res1: String = "未成年です。"」が返って来る。
// 余談
// あれ?結局成人って18歳になったんですよね? 20歳でしたっけ?
(大事) Scala では、「制御構文」は全て「式」
つまり、必ずなんらかの値を返す。
while式
while (条件) {
// 条件が真のあいだ、繰り返す処理
// 無限ループを生まないように注意...(自戒)
}
- 条件が真のあいだ(while)、処理を繰り返す(do)構文
- while式も「式」なので、値を返すが、返すべき値がないので、
Unit型の ()
が返って来る。
var day: Int = 0
// day: Int = 0
while(day <= 7) { // 一週間経過するまで、日にちをインクリメント
println(day + " 日経ちました")
day = day + 1
}
// 出力
// 0 日経ちました
// 1 日経ちました
// 2 日経ちました
// 3 日経ちました
// 4 日経ちました
// 5 日経ちました
// 6 日経ちました
// 7 日経ちました
- dowhile という構文もある
// 0 から 9 まで数え上げる
var i: Int = 0
do {
println("i=" + i)
i = i + 1
} while(i<10)
// 出力
// i=0
// i=1
// i=2
// i=3
// i=4
// i=5
// i=6
// i=7
// i=8
// i=9
dowhileは、コードを読む時に目線が下から上に動かさねばならず、不自然なため、使うことが推奨されないという説もある(あった気がする)。
return式
- 処理の途中で抜け出して、値を返すのに使われる構文
- Scalaでは、式は必ず返り値を持つので、他の多くのプログラミング言語と違い、returnは必ず必要という訳ではないのだが、上手に使うと読みやすいコードを作ることができる(こともある)。
for式
for (繰り返し変数 <- 繰り返し範囲) {
// 繰り返し範囲にある間、繰り返される処理
}
- 「for文」の拡張とも言える構文
- 多重ループも1文でかける。
- ループの条件指定が2通りある(
to
とuntil
)
// to:
// 「x <- a to b」 で「a以上b以下」の範囲でループする。
for(x <- 1 to 5){
println("x = " + x)
}
// (出力)
// x = 1
// x = 2
// x = 3
// x = 4
// x = 5
// until:
// 「y <- a to b」 で「a以上b未満 (b-1以下)」の範囲でループする。
for(y <- 1 until 5){
println("y = " + y)
}
// (出力)
// y = 1
// y = 2
// y = 3
// y = 4
- 二重ループ
// x: 1 ~ 5 まで & y: 1 ~ 4 まで総当たりの順列
for(x <- 1 to 5; y <- 1 until 5){
println("x = " + x + ", y = " + y)
}
/* 出力 ここから
x = 1, y = 1
x = 1, y = 2
x = 1, y = 3
x = 1, y = 4
x = 2, y = 1
x = 2, y = 2
x = 2, y = 3
x = 2, y = 4
x = 3, y = 1
x = 3, y = 2
x = 3, y = 3
x = 3, y = 4
x = 4, y = 1
x = 4, y = 2
x = 4, y = 3
x = 4, y = 4
x = 5, y = 1
x = 5, y = 2
x = 5, y = 3
x = 5, y = 4
出力 ここまで */
- ループ内に条件指定することもできる。
// x: 1 ~ 5 まで & y: 1 ~ 4 まで総当たりの順列で、
// x と y が同じ値を持つ、ならば、println()する
for(x <- 1 to 5; y <- 1 until 5; if x == y){
println("x = " + x + ", y = " + y)
}
x = 1, y = 1
x = 2, y = 2
x = 3, y = 3
x = 4, y = 4
/* 出力
x = 1, y = 1
x = 2, y = 2
x = 3, y = 3
x = 4, y = 4
確かに指定した条件の通りになっている */
FizzBuzz
ここまでの制御構文の知識があればFizzBuzzが書けそうだったので、書いてみました。
Main.scala
object Main {
def main(args: Array[String]): Unit = {
for (i <- 1 to 100) {
if (i%15 == 0) {
println(i + ": FizzBuzz")
} else if (i%3 == 0) {
println(i + ": Fizz")
} else if (i%5 == 0) {
println(i + ": Buzz")
} else {
println(i)
}
}
}
}
scala Main.scala
もしくは
$ scalac Main.scala
$ scala Main
とりあえず、ここまで。
奥が深そうなので、追加で勉強したことがあったら順次記載していきたいと思います。
参考
- ドワンゴ 新卒エンジニア向けの研修資料
- Scalaプログラムの基本(まとめ)
-
第一章:猿でも分かるScala!
どうして猿を引き合いに出したがるのか...