この記事は?
Scalaスケーラブルプログラミング第3版を読んで、個人的に気になった箇所や勉強になった箇所のまとめです。
認識誤りなどがあればご指摘いただけると幸いです。
1章のまとめはこちら
第2章 Scalaプログラミングの第一歩
変数は2種類ある
var
は何度でも代入可能な変数。
val
は初期化後別の値を代入できない変数。
関数定義の仕方
基本的には以下のように定義するが、省略可能なものもある。
関数が1文のみの場合中カッコは省略できる。
Javaではメソッドが返す値の型を「戻り値(return type)」と言うが、Scalaでは「結果型(result type)」と呼ぶ。
def max(x: Int, y: Int): Int = {
if (x > y)
x
else
y
}
関数が意味のある値を返さない場合Unit型が返る
Unit型はJavaのvoidに似ており、Javaのvoidを返すメソッドはUnitを返すメソッドにマッピングされる。
scala> def greet() = println("Hello, World!")
greet: ()Unit
配列の要素にアクセスするときは()
を使う
Javaでは配列の要素にアクセスする場合は[]
を使用するがScalaでは()
を使用する
// これはJava
String hoge = args[0]
// これはScala
val hoge = args(0)
while
とif
は基本的にJavaと同じ
以下のようにScalaのwhile
とif
は基本的にJavaと同じ
var i = 0
while (i < args.length) {
if (i != 0) // Java同様に中カッコを省略することもできる
print(" ")
print(args(i))
i += 1
}
foreach
は関数リテラル、右矢印、関数本体を使う
関数リテラルの構文は以下のように関数パラメータ、右矢印、関数本体の3つからなる
(x: Int, y: Int) => x + y
下の例ではarg
が関数リテラルでprintln(arg)
が関数本体である。
// 例
args.foreach(arg => println(arg))
また関数リテラルが1個の引数をとる1文から成る場合は引数を省略できる
args.foreach(println)
for式
では<-
を使う
// 例
for (arg <- args)
println(arg)
上の例のarg
は必ずval
になる。
<-
は「in」と読むと理解しやすいかもしれない。
for (arg in args)
第3章 Scalaプログラミングの次の一歩
Scalaではnew
を使ってインスタンスを生成できる
インスタンスを生成する際に型を指定することもできる
val hoge = new Array[String](3)
Scalaではすべての演算がメソッド呼び出し
1 + 2
は(1).+(2)
と同じで1
の+
メソッドを呼び出し引数に2
を渡している
配列の要素アクセスや初期化も同様にメソッドを呼び出している
// 要素アクセス
hoge(0) と hoge.apply(0) は同じ
hoge(0) = "piyo" と hoge.update(0, "piyo") は同じ
// 初期化
val numNames = Array("zero", "one", "two") は
val numNames = Array.apply("zero", "one", "two") と同じ
ScalaのListはイミュータブルである
リストの内容を変更するようなメソッドを呼ぶと、新しい値を持つ新しいリストが作成され、返される。
例えば::
はリストの先頭に新しい要素を追加して得られるリストを返す。
scala> val oneTwoThree = 1 :: 2 :: 3 :: Nil
oneTwoThree: List[Int] = List(1, 2, 3)
ちなみにListを初期化する場合は最後にNil
をつける必要がある。
scala> val oneTwoThreeFour = 1 :: 2 :: 3 :: 4
<console>:7: error: value :: is not a member of Int
val oneTwoThreeFour = 1 :: 2 :: 3 :: 4
^
scala> val oneTwoThreeFour = 1 :: 2 :: 3 :: 4 :: Nil
oneTwoThreeFour: List[Int] = List(1, 2, 3, 4)
タプル(tuple)はリスト同様イミュータブルだが、異なる方の要素を持つことができる
タプルの個々の要素にアクセスするには._
と1から始まる要素の番号を指定する
scala> val messi = ("Barcelona", 10)
messi: (String, Int) = (Barcelona,10)
scala> messi._1
res14: String = Barcelona
scala> messi._2
res15: Int = 10
集合(Set)とマップ(map)にはミュータブルなものとイミュータブルなものがある
Setはデフォルトだとイミュータブルになる
//デフォルトだとイミュータブルなSetインスタンスが返る
scala> var realMadrid = Set("Ronald", "Ramos", "Isco", "Modric")
realMadrid: scala.collection.immutable.Set[String] = Set(Ronald, Ramos, Isco, Modric)
// 新しい要素を追加するとイミュータブルなSetの場合、新しいインスタンスを返す
scala> realMadrid + "Kroos"
res16: scala.collection.immutable.Set[String] = Set(Ronald, Kroos, Ramos, Modric, Isco)
// 元のインスタンスの要素は変わっていない
scala> realMadrid
res17: scala.collection.immutable.Set[String] = Set(Ronald, Ramos, Isco, Modric)
ミュータブルなSetを使うにはimportが必要
scala> import scala.collection.mutable
import scala.collection.mutable
scala> val bigFour = mutable.Set("Federer", "Nadal", "Djokovic")
bigFour: scala.collection.mutable.Set[String] = Set(Djokovic, Nadal, Federer)
scala> bigFour += "Murray"
res18: bigFour.type = Set(Djokovic, Nadal, Murray, Federer)
scala> bigFour
res19: scala.collection.mutable.Set[String] = Set(Djokovic, Nadal, Murray, Federer)
Mapもデフォルトはイミュータブルで、ミュータブルなMapを作るにはimportする必要がある。
scala> val artists = Map(1 -> "Suchmos", 2 -> "BUMP OF CHICKEN", 3 -> "Utada Hikaru")
artists: scala.collection.immutable.Map[Int,String] = Map(1 -> Suchmos, 2 -> BUMP OF CHICKEN, 3 -> Utada Hikaru)
scala> import scala.collection.mutable
import scala.collection.mutable
scala> val rappers = mutable.Map(1 -> "Jay-Z", 2 -> "Nas")
rappers: scala.collection.mutable.Map[Int,String] = Map(2 -> Nas, 1 -> Jay-Z)
scala> rappers += (3 -> "Q-Tip")
res20: rappers.type = Map(2 -> Nas, 1 -> Jay-Z, 3 -> Q-Tip)
scala> rappers
res21: scala.collection.mutable.Map[Int,String] = Map(2 -> Nas, 1 -> Jay-Z, 3 -> Q-Tip)
関数型のスタイルに近づくにはvar
を使わないことが大事
// これは命令型スタイル
def printArgs(args : Array[String]): Unit = {
var i = 0
while(i < args.length) {
println(args.(i))
i += 1
}
}
// これは関数型スタイル(純粋な関数型ではない!)
def printArgs(args : Array[String]): Unit = {
args.foreach(println)
}
純粋な関数型は副作用を持たない。結果型がUnit
になっていると副作用があることを意味している。