LoginSignup
1
0

More than 3 years have passed since last update.

ゼロから始めるScala (制御構文編)

Last updated at Posted at 2020-06-30

Scala をはじめよう 第2回目

今回はScalaの制御構文をまとめてみたい。

実行環境 (review)

前回構築したscalaorsbtを用いる

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通りある(tountil)
// 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

とりあえず、ここまで。
奥が深そうなので、追加で勉強したことがあったら順次記載していきたいと思います。

参考

1
0
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
1
0