先日、Scala 2.9.0 RC4がリリースされ、正式リリース(final)までもうあと少しといった感じになって来ましたが、皆様、いかがお過ごしでしょうか。訓練されたScala使いはRCには手を出さないとも言われますが、私は新し物好きなので、RCにも手を出してしまいます。
それはともかくとして、Scala 2.9.0の最大の目玉は何でしょうか?世間的(どこの世間だというツッコミはおいといて)には並列コレクションではないでしょうか。Scalaの公式サイトでも新機能の紹介で真っ先に挙げられていますし、少なくとも一番注目されているのは並列コレクションでしょう。
並列コレクションは、公式サイトも含め、英語圏のブログなどあちこちで既に紹介されているので、このエントリではあえて、その陰に隠れてあまり注目されないが、なかなか便利なscala.sys.processパッケージについて紹介します。
scala.sys.processパッケージは元々はsbtというScala用のビルドツールのAPIで、外部プロセスの実行・リダイレクト・パイプなどを簡単に行えるAPIでしたが、便利なのでScala本家にも輸入された、という代物です。実際使ってみるとわかりますが、大変便利です。
とりあえず、長ったらしい紹介は抜きにしてREPLで逐一試していきましょう。
scala> import scala.sys.process._ import scala.sys.process._
まずはお決まりのimport文です。ここで、_でscala.sys.processパッケージ下のメンバを全てimportしているのは、後で意味を持ってきます。
さて、とりあえず使ってみましょう。
scala> Process("ls") run res0: scala.sys.process.Process = scala.sys.process.ProcessImpl$SimpleProcess@1d 1358f bar.txt dir.txt foo.txt hoge.txt
Process("ls") run
の一行だけで、lsが実行されて、結果が標準出力に出力されていますね。もちろん、標準出力に出力するだけでなく、リダイレクトにも対応しています。
scala> Process("ls") #> new java.io.File("ls_result.txt") run res2: scala.sys.process.Process = scala.sys.process.ProcessImpl$PipedProcesses@b 04589
ls_result.txtの中身を見てみると、
bar.txt dir.txt foo.txt hoge.txt ls_result.txt
となっており、ちゃんとファイルに書き込まれていることがわかります。
当然の事ながら(?)、パイプにも対応しています。
scala> Process("ls") #| Process("sort") run res7: scala.sys.process.Process = scala.sys.process.ProcessImpl$PipedProcesses@1 99ef99 bar.txt dir.txt foo.txt hoge.txt ls_result.txt
さらに、プロセスの実行結果をそのまま文字列として取得することもできます。
scala> val result = Process("ls") !! result: String = "bar.txt dir.txt foo.txt hoge.txt ls_result.txt "
!!
演算子を呼び出すと、対象のプロセスを実行し、その標準出力の出力結果をStringとして返してくれます。
また、出力結果を行ごとに得ることもできます。
scala> val result = Process("ls").lines.toList result: List[String] = List(bar.txt, dir.txt, foo.txt, hoge.txt, ls_result.txt)
このように、scala.sys.processパッケージは、外部プロセスを簡単に実行して、その結果をScalaプログラム中で利用するにはかなり便利なライブラリです。
しかし、scala.sys.processの本領はこんなものではありません。
scala> "ls" run res4: scala.sys.process.Process = scala.sys.process.ProcessImpl$SimpleProcess@1d 529be bar.txt dir.txt foo.txt hoge.txt ls_result.txt
なんと、いきなり文字列に対してrunメソッドを呼び出すことができています。実は、scala.sys.processパッケージはパッケージオブジェクトになっており、そのメンバとして、implicit conversionが定義されているので、このような事が可能になっているのです。
とまあ、駆け足でscala.sys.processパッケージについて紹介してみましたが、いかがでしたでしょうか。他にも、scala.sys.processパッケージには便利な機能が多数あるので、是非、試してみてください。