日々精進

aikoと旅行とプログラミング

はじめてのScala【コップ本第2章】

【ステップ1】Scalaインタプリタの使い方を学ぶ

今回はsbtをインストールし,そこからコンソールを使うことにした.

$ set console
[info] Set current project to **** (in build file:*******)
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_101).
Type in expressions to have them evaluated.
Type :help for more information.

とりあえずお約束のHello, world!

scala> println("Hello, world!")
Hello, world!

printlnはjavaのSystem.out.println関数と同様標準出力に出力をする。次に数式だけ打ってみる。

scala> 1+2
res0: Int = 3

次のように出力される。res0というのは自動生成された変数名であり、Int型であることがわかる。式を評価した結果,、es0に3がセットされる。 res0に3がセットされているので,以下の様な処理も可能である。

scala> res0 * 3
res3: Int = 9

【ステップ2】変数を定義する

Scalaにはvalとvarという二種類の変数が存在する。valはjavaでいうところのfinal変数と似た振る舞いをする。そのため、値の再代入をすることが出来ない。(代入するとエラーになる) それに対してvarは再代入が可能であるが、できるだけvalを使うコードを書くべきである。

scala> val msg = "Hello, world!"
msg: String = Hello, world!

Scalaでは型推論が行われており、"Hello, world!"を見てStringと判断し、msgの型をStringとしている。
もちろん明示的に型を設定することもできる。

scala> val msg2: String = "Hello again, world!"
msg2: String = Hello again, world!
scala> println(msg2)
Hello again, world!

(val | var) 変数名: 型 = 値のフォーマットで書くことができる。

【ステップ3】関数を定義する

Scalaの関数は以下の様なフォーマットでかく、

scala> def max(x: Int, y: Int): Int = {
     |   if(x > y) x
     |   else y
     | }
max: (x: Int, y: Int)Int

まず関数を定義する際には

  • 先頭にdefと書き(def)
  • 続けて関数名を書く. (max)
  • 関数のパラメータは型推論を行わないため、明示的に指定する必要がある。(x: Int, y: Int)
  • そして、関数自体が返す値の型(結果型)を指定する。 : Int
  • その後統合を記述し、中括弧で囲んだ中身が本体となる。

f:id:bath_poo:20160805184703p:plain

パラメータは明示的に型を示す必要があるが、結果型に関してはこの限りではない。例えば再帰呼び出しをするようなプログラムに関しては結果型の指定が必要であるが、今回のmax関数のような場合は書かなくてもコンパイラが自動的に推論してくれる。しかし、明示的に書いたほうがコードが書きやすくなるので書いたほうがベターである。

関数の中身が1行で構成されてる場合は中括弧を省略して書くことができる。

scala> def max2(x: Int, y: Int): Int = if(x > y) x else y
max2: (x: Int, y: Int)Int
scala> max(3, 5)
res6: Int = 5

続いては、意味のある結果を返さない関数の例である。

scala> def greet() = println("Hello, world!");
greet: ()Unit

結果型がUnitとなっており、関数が意味のある値を返していないことを示している。結果型がUnit型であるメソッドは、副作用のある関数で用いられる。関数型自体初めてなので副作用という単語で詰まったが、何かを与えたら何かを返すのを前提にプログラムを書こうという話で、ほかの箇所に影響を与えないようにしようねという話っぽい(詳しくはまた勉強します)

【ステップ4】簡単なScalaスクリプトを書く

スクリプトファイルの用に書くこともできる。例えば

println("Hello, world, from a script!");

をhello.scalaというファイル名で保存し、

$ scala hello.scala

とすると

Hello, world, from a script!

と出力される。
Scalaにもコマンドライン引数があり、argsというScala配列に格納されている。アクセスするときはargs(0)やargs(1)のようにアクセスする。(Javaのようにargs[0], args[1]とは書かない)

println("Hello " + args(0) + "!");

として

$ scala helloargs.scala planet

とすると

Hello planet!

のように出力される。

【ステップ5】whileによるループ、ifによる分岐

whileループ
var i = 0
while(i < args.length){
  println(args(i))
  i += 1
}

このように命令形で書くことも一応できる。が、今回の目的はこれではないのでスルー

【ステップ6】foreachとforによる反復実行

以下の様なJavaC++のような命令形のコードは

var i = 0
while(i < args.length){
  println(args(i))
  i += 1
}

次のような関数型のスタイルで書くことができる。

args.foreach(arg -> println(arg))

argsのforeachメソッドを呼び出し、引数として関数リテラルを渡している。関数リテラルも明示的に型を定義することができる。

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

但し引数部分はカッコで囲まなくてはならない。

args.foreach(println)

引数が1つの関数リテラルは、引数を明示的に指定しなくて良いため、上記のコードでも同じ振る舞いをする。これは部分適用された関数と呼ばれている。

forループ

命令形のfor文に対応するものとして、for式というものがある。以下にコード例を示す。

for(arg <- args){
  println(arg)
}

とすると、

$ scala forargs.scala for arg in args
for
arg
in
args

for式中にある<-記号の左側の変数は常にvalである。<-をinとよめば、for arg in argsとなり、集合の"∈"に対応する。