「Scalaスケーラブルプログラミング」で気になったところまとめ ~ 2章&3章 ~
この記事は?
- 作者: Martin Odersky,Lex Spoon,Bill Venners,羽生田栄一,水島宏太,長尾高弘
- 出版社/メーカー: インプレス
- 発売日: 2016/09/20
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (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
になっていると副作用があることを意味している。