のーずいだんぷ

主に自分用メモですが、もしかしたら誰かの役に立つかもしれません

Scalaマスターになりたくて ~変数と関数と条件分岐とループ~

一日一文法シリーズ改め…

先日Pythonでやっていたこの一日一文法シリーズ、流石に忙しいときはブログ1件が精一杯で、とういうよりは会社の仕事を家でも終わるまで詰め込みでやってしまうので、 自分のコードを一切書かない日々が続いていた。 個人的にPythonとScalaはちゃんと極めたい気持ちがあるので、webでざっと調べるのではなくちゃんと基礎から勉強していく。 ということで、途切れてしまっていたのだが、このシリーズについては別の名称に改名して文法を学ぶシリーズとして不定期で継続していこうと思う。 名前は正直個人的なモチベーションが全てなのでどうでもいいが、Scalaに関しては「Scalaマスターになりたくて」で進めていこうと思う。

書籍はもちろんコップ本を使う。まだところどころしか読んでいないが、控えめに言って素晴らしい本。Scalaプログラマは絶対に3冊は持っていると思う(第3版まで)。

Scalaスケーラブルプログラミング第3版

Scalaスケーラブルプログラミング第3版

  • 作者: Martin Odersky,Lex Spoon,Bill Venners,羽生田栄一,水島宏太,長尾高弘
  • 出版社/メーカー: インプレス
  • 発売日: 2016/09/20
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログ (1件) を見る

しょうもないことについてもざっくりメモをとって本が無くても見てわかるようなものにしたい。

変数宣言

Scalaでは二種類の変数宣言ができる。 前者が再代入可能な変数で、後者が再代入不可能なものになる。

var test_value = "再代入可能"

val test_value = "再代入不可能"

一応REPLで確認しておく。

scala> val test_value = "first"
test_value: String = first

scala> test_value = "second"
                  ^
       error: reassignment to val

ちなみに、静的型付けだからといってJavaのようにString型で有ることを明示的に示す必要はない。 Scalaの場合、強力な型推論があるため、今回のケースでは代入されている値からその型を推論する。

もちろん意図的に型を指定することも可能であり、その場合:をの右側に型を記載する。

val test_value :String

形式としてはPythonやRubyのダックタイピングのやり方やTypeScriptと同じといえる。

関数の定義

Scalaのおける関数は次のように定義する。

def <関数名>([引数]) [:戻り値型] = { [処理の内容] }

具体的な例を見てみる。

scala> def show(num:Int, value:String):Unit = {
     | println(s"num:$num, value:$value")
     | }
show: (num: Int, value: String)Unit

基本的にはJavaの構文に似た形になっていると思う。 いくつか大事なポイントがある。

  • returnはない。最後の行のが評価された結果が戻り値として返却される。
  • 戻り値型の右の=は重要。なくすと戻り値が強制的にUnit型であるとコンパイラが解釈する。(Procedure Syntaxというらしい)

変哲もない関数だが、一応実行してみる。

scala> show(3, "Hello, World")
num:3, value:Hello, World

無事に想定通りの動作が確認できた。

例に関する細かい話

Unit型とは

ちなみに細かいが、Unitは返却される値がない(void型とは若干定義が異なる)ことを返す型である。 ここでは一旦厳密な説明は避け、また型についてのトピックの際に詳細に確認する。 ここで理解が必要なのは、値がないという返却値がある、ということである。

Scalaのクオート

基本的にはJavaと同じ扱いとなっているようだ。

  • ダブルクオート→文字列リテラル
  • シングルクオート→文字リテラル

ちなみに例のようにs"文字列$変数"とすると、文字列内に変数を埋め込むことができる。

条件分岐とループ

whileとif-else

ScalaではJavaと同様に以下のようにループと条件分岐を定義する。

  • 条件分岐:if(条件式){<処理>}
  • ループ:while(条件式){ <処理> }

具体的には以下のように記載する。

var i = 0

while(i<args.length){
  if (i%2 == 0)
  println(args(i))
  else
  println("奇数")

  i+=1
}

実行結果は以下のようになる。

 $ scala loop.scala 1 2 3 4 5 6
1
奇数
3
奇数
5
奇数

定義とほとんど同じなので特段説明することはないが、if~elseについては処理が1行で記述できる場合、中括弧({})が不要になるという点には注意したい。 また本筋とは無関係であるが、Scalaは増分演算子を+=で記述する(++)は使えない。

foreachとforによるループ

whileによる書き方は、いわゆる「命令型」と呼ばれる書き方で、一般的なプログラミング言語ではこの書き方で書かれている。 Scalaでは「関数型」と呼ばれる書き方で記述することができ、この書き方により前者の書き方と比較して簡潔に記述できる場合がおおい。 正直現時点ではこれらの本質について理解できていないので、また別途勉強した際にまとめようと思う。

実際にどう書くことができるのか例を見てみる。

args.foreach((arg: String) => println(arg))

上記の例では、配列argsの各要素を順番に関数本体println()に渡すような動作となる。 この時一時変数のようなargのことを関数リテラルと呼ぶ。ちなみに今回のケースではこれを以下のように省略して書くことができる。

args.foreach(println)

順序が逆になってしまったが、一般化した構造は以下のようになる。

(<関数リテラル>) => <関数>

JavaScriptのアロー関数と同じ記法になる。 もちろんこれらの処理は従来と同じ命令型の記法で書くことも可能である。

for (arg <- args)
  println(arg)

実際はScalaのfor文はもっと強力なものらしい。また以降の章を学習した後にまとめたい。

参考

www.slideshare.net