🔍

手を動かしてわかる Scala のスコープ ─ 九九表で学ぶ変数の見える範囲とリファクタリング

に公開

Scala のスコープを “手を動かして” 体感しよう 🔥

1. まずは REPL を開こう

ターミナルで scala (または Ammonite 派なら amm )と叩いて REPL を起動してください。

$ scala
Welcome to Scala 2.13.16 (OpenJDK 64-Bit Server VM, Java 17.0.15).
Type in expressions for evaluation. Or try :help.

以降、 scala> の行は コピペして Enter するだけで OK です!

2. かけ算九九表を while で書いてみる

まずは本の例そのまんま、命令型スタイルの printMultiTable を REPL に貼り付けてみましょう。

def printMultiTable(): Unit = {

  var i = 1                 // ← ここでは i がスコープにいる

  while (i <= 10) {
    var j = 1               // ← ここでは i と j が見える

    while (j <= 10) {
      val prod = (i * j).toString  // ← i, j, prod が見える
      var k = prod.length          // ← i, j, prod, k が見える

      while (k < 4) {
        print(" ")
        k += 1
      }
      print(prod)
      j += 1
    }
    println()               // ← i だけ見える。j, prod, k は見えない
    i += 1
  }
}
scala> printMultiTable()
  1  2  3 ... 10   // ← ちゃんと九九表が出れば成功!

3. シャドウイングって何?(val a の実験)

同じスコープに 同じ名前の変数 は定義できません。
でも “外”“内” であれば 上書き(シャドウイング) できます。

val a = 1
{
  val a = 2      // ← 外側の a を “隠す” 新しい a
  println(a)     // => 2
}
println(a)       // => 1
  • 中カッコの中では 内側 a = 2 が見える
  • 外に出ると 外側 a = 1 が見える

これがシャドウイングです。
個人の好みですが、可読性重視なら なるべく違う名前 を付けた方が吉です。

4. 関数型っぽくリファクタしてみる ✨

while と var で書いた printMultiTable を、 val + for 式 + ヘルパー関数 で書き換えるとこうなります。

// 1段分を Seq[String] で返す
def makeRowSeq(row: Int) =
  for (col <- 1 to 10) yield {
    val prod     = (row * col).toString
    val padding  = " " * (4 - prod.length)
    padding + prod
  }

// 1段を String に連結
def makeRow(row: Int) = makeRowSeq(row).mkString

// 表全体を 1つの文字列に
def multiTable() = {
  val tableSeq =
    for (row <- 1 to 10)
      yield makeRow(row)
  tableSeq.mkString("\n")
}
scala> println(multiTable())
   1   2   3 ...  10
   2   4   6 ...  20
   3   6   9 ...  30
   ...
  10 ...             100

どこがうれしい?

命令型 (while) 関数型 (for + val)
状態を更新する変数 i, j, k が大量に出てくる val なので再代入ナシ、バグりにくい
“計算 + 出力” が入り混じる 副作用ゼロ の関数 (multiTable はただの文字列を返す)
ユニットテストしづらい 返り値の文字列を比較するだけでテスト可

5. まとめ 🎯

  • Scala では {} を開くたびに新しいスコープ ができる
  • 同じスコープで同じ名前は NG、でも内側でなら シャドウイング できる
  • while & var で書いたら、一度 val + for 式 に置き換えてみよう
    • 副作用が減り、テストしやすくなる

Scala に疲れたら ☕ を飲みつつ、小さなスクリプトで “実験 → 体感” を繰り返すと理解がグッと深まります。Enjoy Scala!

参考文献

  • Martin Odersky, Lex Spoon, Bill Venners, Scalaスケーラブルプログラミング 第4版, オライリー・ジャパン, 2021, 第7章より着想を得て執筆。

Discussion