気になる開発プロダクツ

第7回 Scala 2.6.0-final

この記事を読むのに必要な時間:およそ 6 分

Rubyのブロックのような処理ができる

Scalaでは,Rubyでいうブロックのような処理を行うメソッドが用意されています。yieldという,ブロックを実行するメソッドもありますので,Rubyに近いプログラミングが可能です。図12がScalaのメソッド,図13がRubyのブロックの例です。両者でメソッド名や戻り値が異なる場合もありますが,ほぼ同じ処理が実行できることがわかります。

図12 Rubyのブロックのような処理

scala> (1 to 5).foreach( x => println( x ) )  ← 1から5までの値を表示
1
2
3
4
5

scala> (1 to 5).map( x => x * x )       ← 1から5までの値をそれぞれ2乗
res0: RandomAccessSeq.Projection[Int] = RangeM(1, 4, 9, 16, 25)

scala> (1 to 5).filter( x => x > 3 )    ← 3より大きな要素のみを抽出
res1: Seq.Projection[Int] = RangeF(4, 5)

scala> for( x <- 1 to 5 ) yield x * x   ← yieldも使える
res2: RandomAccessSeq.Projection[Int] = RangeM(1, 4, 9, 16, 25)

scala> def sqr( n : Int ) = for( x <- 1 to n ) yield x * x
dup: (Int)RandomAccessSeq.Projection[Int]

scala> sqr( 5 ).foreach( s => println( s ) )
1
4
9
16
25

図13 Rubyのブロック処理(参考) -irbで実行

> irb
irb(main):001:0> (1..5).each { |x| puts x }
1
2
3
4
5
=> 1..5
irb(main):002:0> (1..5).map { |x| x * x }
=> [1, 4, 9, 16, 25]
irb(main):003:0> (1..5).find_all { |x| x > 3 }
=> [4, 5]
irb(main):004:0> def sqr( n )  for x in 1..n; yield x * x; end end
=> nil
irb(main):005:0> sqr( 5 ) { |s| puts s }
1
4
9
16
25
=> 1..5
irb(main):006:0>

リストや配列ではないタプル

IPアドレスやデータベースのテーブルの1行分のデータのように,複数の要素が集まって1つの集合になっている値というものが存在します。それがタプル(Tuple)です。いったん定義された要素は更新できないというのがリストや配列とは異なる特徴です。PythonXQueryでもタプルの定義が可能になっています。

タプルの要素は左から_1, _2, ...のように指定します。図14に例を示します。

図14 タプルの要素の指定

scala> var p = (3.0, 4.0)
p: (Double, Double) = (3.0,4.0)

scala> var x = p._1
x: Double = 3.0

scala> var y = p._2
y: Double = 4.0

scala> Math.sqrt( x * x + y * y )
res0: Double = 5.0

scala>

"""~"""とXML

複数行にわたる長い文字列は"""~"""で記述できます。これはPythonと同じです。そしてXML自体をソースコードに記述できます。これはXQueryと同じです。ソースコード内にこうしたものが記述されているのはJavaプログラマにとっては驚きかもしれませんが,PythonやXQueryの世界ではあたりまえのことなのです。その両方を体験できるScalaは貴重な存在ではないかと思います。

図15に示すとおり,XMLデータが代入された場合は,\や\\を用いて必要なノードのみを抽出することもできます。これはXPathの/や//を真似たものと推測できます。

図15 """~"""とXMLの代入

scala> var html = """<html>
     | <head><title>Scalaでプログラミング</title></head>
     | <body><h1>その1 基本的なこと</h1></body>
     | </html>"""
html: java.lang.String =
<html>
<head><title>Scalaでプログラミング</title></head>
<body><h1>その1 基本的なこと</h1></body>
</html>

scala> var xml = <html>
     | <head><title>Scalaでプログラミング</title></head>
     | <body><h1>その1 基本的なこと</h1></body>
     | </html>
xml: scala.xml.Elem =
<html>
<head><title>Scalaでプログラミング</title></head>
<body><h1>その1 基本的なこと</h1></body>
</html>

scala> xml \ "head"
res0: scala.xml.NodeSeq = <head><title>Scalaでプログラミング</title></head>

scala> xml \ "body"
res1: scala.xml.NodeSeq = <body><h1>その1 基本的なこと</h1></body>

scala> xml \\ "title"
res2: scala.xml.NodeSeq = <title>Scalaでプログラミング</title>

scala> xml \\ "h1"
res3: scala.xml.NodeSeq = <h1>その1 基本的なこと</h1>

scala>

.や()をつけなくてもよい

Javaプログラミングでは,メソッド名の前には.(ピリオド)がつき,引数を囲むのには()が必要です。しかしScalaでは,図16のように,空白で区切られたものの意味や優先順位が明白であれば,これらを記述しなくても動作する場合があります。

図16 .や()がなくても動作する

scala> Math.sqrt( 5.0 )  ← Javaでは一般的な記述
res18: Double = 2.23606797749979

scala> Math sqrt 5.0     ← .や()を記述しなくても動作する
res19: Double = 2.23606797749979

scala> 1 to 5 foreach x => println x   ← 優先順位が不明確でうまく動作しない
<console>:1: error: not a legal formal parameter
1 to 5 foreach x => println x
       ^

scala> (1 to 5).foreach( x => println( x ) )  ← ()で優先順位を示せば動作する
1
2
3
4
5

scala>

今回紹介できたのはScalaプログラミングのほんの入り口に過ぎません。その先にはJavaでは体験できない世界が遠くまで広がっています。サンプルソースなどを参照しながら,新しい体験をしてみてください。これまで見えていなかったものが見えてくるかもしれません。

著者プロフィール

沖林正紀(おきばやしまさのり)

SE/プログラマを経て,WebアプリケーションやXMLなどについて雑誌記事や書籍の執筆活動を始める。大手メーカで製品資料の作成や,セミナーの講師を担当したこともある。現在は,取材記事や製品レビューなどに執筆活動の幅を広げる一方,プログラミング教材の開発も手がけている。

著書