ikeike443のブログ

ソフトウェアビジネスに関心がある系のブログ

メモ

Scala勉強中


Collectionについていろいろ試してみた。
結論もなければ整理もしてないので悪しからず。。


MapやListに関数を入れられる

scala> val m = Map("func" -> {i:Int=>i*3})
m: scala.collection.immutable.Map[java.lang.String,Int => Int] = Map(func -> <function1>)

でもgetやgetOrElseで取り出すと

scala> m.getOrElse("func", None)
res71: ScalaObject = <function1>
上手く実行できない
scala> m.getOrElse("func", None)(3)
<console>:9: error: ScalaObject does not take parameters
              m.getOrElse("func", None)(3)
                                       ^

どうもOptionで包まれて返ってくる値を上手く取り出すにはMatchを使うのがいいっぽい。

scala> m.get("func") match{
     |   case Some(f) => f(2)
     |   case None => "none"
     | }
res68: Any = 6

こうすると中身を上手く取り出せるが、Any, Some, Optionの意味がまだ分かってない。

ごちゃ混ぜのMapも書ける

scala> val m = Map("func" -> {i:Int=>i*2}, "name" -> "ikeda", 3 -> "number", ("localhost", 9000) -> "Play")
m: scala.collection.immutable.Map[Any,java.lang.Object] = Map(func -> <function1>, name -> ikeda, 3 -> number, (localhost,9000) -> Play)

下記のように書いたら取り出せるかとおもいきやコンパイルエラー。

scala> m.foreach {
     |   case (function1, f) => f(3)
     |   case Some(v) => v
     |   case ((String,Int),name) => name
     |   case None => "none"
     | }

getOrElseで取り出しても、Any,Objectになっちゃうから、関数として取り出せないっぽい?

scala> m.getOrElse("func",0)
res3: Any = <function1>

scala> val f = m.getOrElse("func",0)
f: Any = <function1>

scala> f
res4: Any = <function1>

scala> f(3)
<console>:10: error: Any does not take parameters
              f(3)
               ^

scala> val f:function1 = m.getOrElse("func", {})
<console>:8: error: not found: type function1
       val f:function1 = m.getOrElse("func", {})
             ^

scala> val f:Function1 = m.getOrElse("func", {})
<console>:8: error: trait Function1 takes type parameters
       val f:Function1 = m.getOrElse("func", {})
             ^

scala> val f:Function1[function1] = m.getOrElse("func", {})
<console>:8: error: wrong number of type arguments for Function1, should be 2
       val f:Function1[function1] = m.getOrElse("func", {})
             ^

scala> val f:Function1[Int,Int] = m.getOrElse("func", {})
<console>:8: error: type mismatch;
 found   : Unit
 required: Int => Int
       val f:Function1[Int,Int] = m.getOrElse("func", {})
                                                      ^

scala> val f:Function1[Int,Int] = m.getOrElse("func", None)
<console>:8: error: type mismatch;
 found   : None.type (with underlying type object None)
 required: Int => Int
       val f:Function1[Int,Int] = m.getOrElse("func", None)
                                                      ^

scala> val f:Function1[Int,Int] = m.getOrElse("func", {i:Int=>1})
<console>:8: error: type mismatch;
 found   : java.lang.Object
 required: Int => Int
       val f:Function1[Int,Int] = m.getOrElse("func", {i:Int=>1})
                                             ^

scala> val f:Function1[Int,Int] = m.getOrElse[Function1[Int,Int]]("func", {i:Int=>1})
<console>:8: error: type arguments [Int => Int] do not conform to method getOrElse's type parameter bounds [B1 >: java.lang.Object]
       val f:Function1[Int,Int] = m.getOrElse[Function1[Int,Int]]("func", {i:Int=>1})
                                             ^

scala> m
res6: scala.collection.immutable.Map[Any,java.lang.Object] = Map(func -> <function1>, name -> ikeda, 3 -> number, (localhost,9000) -> Play)

scala> val f:Function1[Int,Int] = m.getOrElse[Function1[Int,Int]]("func", {i:Int=>1})
<console>:8: error: type arguments [Int => Int] do not conform to method getOrElse's type parameter bounds [B1 >: java.lang.Object]
       val f:Function1[Int,Int] = m.getOrElse[Function1[Int,Int]]("func", {i:Int=>1})


map関数

scala> val number = List(1,2,3)
number: List[Int] = List(1, 2, 3)

scala> number.map( (i:Int) => i*2 )
res7: List[Int] = List(2, 4, 6)

これはOK

こうも書ける

scala> val f = (i:Int) => i*2
f: Int => Int = <function1>

scala> number.map(f)
res9: List[Int] = List(2, 4, 6)

こうでも一緒

scala> number.map(f(_))
res12: List[Int] = List(2, 4, 6)

でも、これはNG

scala> number.map(f _)
<console>:10: error: type mismatch;
 found   : () => Int => Int
 required: Int => ?

              number.map(f _)

defで宣言してこうも書ける

scala> def timesTwo(i:Int) = i*2
timesTwo: (i: Int)Int

scala> number.map(timesTwo _)
res11: List[Int] = List(2, 4, 6)

これもOK

scala> number.map(timesTwo(_))
res13: List[Int] = List(2, 4, 6)

defで宣言した時と、無名関数として作った場合とで挙動が違うっぽい。
引数の渡され方の問題?


これ出来るの結構便利

scala> val (x,y) = number.partition(_>2)
x: List[Int] = List(3)
y: List[Int] = List(1, 2)

scala> x
res23: List[Int] = List(3)

scala> y
res24: List[Int] = List(1, 2)


filterやmapにはコードブロックが渡せて、中でCase書ける。なんでかはわからんが。。

scala> val extensions = Map("steve" -> 100, "bob" -> 101, "joe" -> 201)
extensions: scala.collection.immutable.Map[java.lang.String,Int] = Map(steve -> 100, bob -> 101, joe -> 201)


こんなふうにも書けるし。

scala> extensions.filter( (name: (String,Int)) => name._2 < 200 )
res18: scala.collection.immutable.Map[java.lang.String,Int] = Map(steve -> 100, bob -> 101)

これはダメだけど、

scala> extensions.filter( case (name, ex) => ex < 200 )
<console>:1: error: illegal start of simple expression
       extensions.filter( case (name, ex) => ex < 200 )
                          ^

こうすればOK

scala> extensions.filter({ case (name, ex) => ex < 200 })
res19: scala.collection.immutable.Map[java.lang.String,Int] = Map(steve -> 100, bob -> 101)

こうすればmapもできる。

scala> extensions.map({ case(name,ex) => ex*2 } )
res20: scala.collection.immutable.Iterable[Int] = List(200, 202, 402)

mapしたあとタプルで返せば再びMapになる。

scala> extensions.map({ case(name,ex) => name->ex*2 } )
res21: scala.collection.immutable.Map[java.lang.String,Int] = Map(steve -> 200, bob -> 202, joe -> 402)