昨日、FOLIOさんのオフィスでイベントがあった。めちゃくちゃ行きたかった!!! くやしい!!! のだが、資料がアップされてきているのでホクホクだ。ありがたい。
そんな中でこのような資料があった:
#FOLIO_Meetup 登壇させていただきました!こちら登壇資料です!楽しかったな。https://t.co/c9FGcFYP6Y
— ntaguchi (@nozomitaguchi) 2026年2月27日
資料の本筋からは脱線するのだが、この中で以下のような記述があった:
val sc = new java.util.Scanner(System.In) val n, t, a = sc.nextInt()
この記述には唸ってしまった。このコードを実行すると、ユーザが入力した行ごとにIntが読み込まれ、それぞれn、t、aにアサインされる。Scala、こんなことできるのか!
1 2 3 // => n = 1; t = 2; a = 3
タネ明かしをしよう(人のコードなのに・・・)。このコードは、Iteratorの特性と、Scalaの構文の妙がうまく噛み合ったクールなコードだ。
Iterator
他のたいていの言語がそうであるように、ScalaにもIteratorが実装されている。ScalaのIteratorの実装はJavaの標準ライブラリのIteratorとは独立しているが、基本的なコンセプトは同じだ。
ちょっとした座学をしよう。Iteratorは、next()とhasNext()を実装するだけで成り立つ便利なコレクションだ。たった2つのメソッドから成り立つのに、驚くべきほど強力な抽象を提供してくれる。Iterator[A]はIterableOnce[A]とIterableOnceOps[A, Iterator, Iterator[A]]のサブクラスだ。つまり、「一度だけ値を走査できる」ものの仲間だ。
このIterableOnceOpsが素晴らしくって、驚くほど多くのオペレーションを行うことができる。
mapもflatMapもできるし、foldもforAllもある。たった2つのメソッドを実装するだけで、データの集まりが突然豊穣な道具箱に変貌するのだ。
さて、Iteratorを褒めたところで、それ自体の基本的な使い方は、next()して次のデータを取り出すことだ。
val it = Iterator("All", "Your", "Base") it.next() // => "All" it.next() // => "Your"
この機能はJavaのIteratorでも同じで、next()とhasNext()がある。java.util.Scannerも、Iteratorを継承しているからIteratorの仲間だ。
複数定義
さて、Scalaにはあまり知られていない便利構文が存在する。複数のvalを同時に定義する機能(特に決まった名前はない)だ。
使い方は簡単、ただval x, y, z = ...のように、変数名をカンマでつないで並べるだけだ。これは、val x = ... val y = ... val z = ...と並べて書いたのと等価だ:
val x, y, z = 42 // is equivalent to: val x = 42 val y = 42 val z = 42
これは複数の変数の初期値を定めるのに便利だ。この構文はvarでも使えるから、動的計画法なんかでガチャガチャダイナミックに値をいじるときに重宝しそうだ。
仕様は以下の通り:
(4.1 Value Definitions)
A value definition $ \textsf{val} \, p_1, ..., p_n = e $ is a shorthand for the sequence of value definitions $ \textsf{val} \, p_1 = e; \quad ...; \quad \textsf{val} \, p_n = e $.
合体!!
ここで互いの真価が発揮される!Iteratorのnext()は不純な、つまり純粋ではない、つまり副作用を有している、つまり呼ぶたびに状態が変化して実行環境に影響を与え、結果が変わりうる関数だ。
val sc = java.util.Scanner(System.In) val x, y, z = sc.nextInt()
するとvalで値を束縛するたびに違う値がやってくるから、それぞれに呼び出した順に違う値がやってくる。java.util.Scannerの場合は、Scannerが値を読み取った順で、変数の値を拘束できるのだ!
上掲のコードは、以下に示すコードと等価だ!
val sc = java.util.Scanner(System.In) val x = sc.nextInt() val y = sc.nextInt() val z = sc.nextInt()
これは本当にクールな組み合わせだ。Scalaがこのシンプルな記法(とそれに対する展開ルール)を用意していることで、また別のシンプルなツールであるIteratorとの組み合わせにより、非常に面白い使い方ができるのだ。シンプルとシンプルが相互作用してうまく動いているのを見るのは、大興奮だ!
余談
ちなみにこれだとリストやタプルの値を拘束したいときにどうするの?と聞かれそうだが、心配は無用、リストやタプルのパターンをそのまま書けば良いから、先程までの記法とは衝突しない:
val List(x, y, z) = lis // List()で書く val (t1, t2, t3) = triple // カッコでくくる