scaladocを読むために
scaladoc読んで勉強してても記号が多いのとよく分からないキーワードが出てきて読みづらい。
気になったものを調べてまとめる。
可変長引数
以下はMap#+メソッド。*の部分。
def +(kvs: (A, B)*): Map[A, B]
implicitパラメータ
例えばList#maxByメソッド。
def maxBy[B](f: (A) ⇒ B)(implicit cmp: Ordering[B]): A
implicitが付いているメソッド引数は省略可能。省略すればデフォルトのものが適用されるが、自分で指定することも可能。
まず省略バージョン。
val list = List("one", "two", "three", "four") val result = list.maxBy(_.length) // 一番文字列長の長いthreeが返る
次に並び替えの仕組みを独自Orderingで変える。無名traitを生成して対応。
val result2 = list.maxBy(_.length){ // 一番文字列長の長いthreeが返る new Ordering[Int]{ def compare(x: Int, y: Int) = x - y } } val result3 = list.maxBy(_.length){ // 一番文字列長の短いoneが返る new Ordering[Int]{ def compare(x: Int, y: Int) = y - x } }
implicit付変数宣言をしておくと、第二引数省略してもそれが使用される。
implicit val ordering = new Ordering[Int]{ def compare(x: Int, y: Int) = y - x } val result = list.maxBy(_.length) // one
カリー化されたメソッド
以下はList#foldのscaladoc。
def fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1
このように使う。
val list = List(1,2,3,4) val result = list.fold(10)((e1,e2) => e1 + e2) // 実際の処理は10+1+2+3+4が行われる
ただ、2番目の引数は(ではなく{で記述されることが多い。
val result = list.fold(10){(e1,e2) => e1 + e2}
ジェネリクス
Ancestor > Parent > Childというようなクラス階層になっているとして。
上限境界
以下の例だと、Parent及びサブクラスChild。
class Sample[T <: Parent](x: T) {}
下限境界
以下の例だと、Parent及びスーパークラスAncestor。
class Sample[T >: Parent(x: T) {}
先のfoldメソッドのscaladocをもう一度引用すると
def fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1
となっている。このメソッドで使用するのはA1というAの下限境界型。よって、、、
class Ancestor(var x:Int) {} class Parent(var y:Int) extends Ancestor(y){} class Child(var z:Int) extends Parent(z) {} val list:List[Parent] = List(new Parent(1), new Parent(2)) val result = list.fold(new Ancestor(10)){(e1, e2) => e2.x = e1.x + e2.x; e2;}
List[Parent]に対して、変数zには親のAncestorが渡せる。この場合、A1はAncestorになるので、e1.xというアクセスになる。
一方、変数zのところを、new Parent(10)としたならば、e1.xではコンパイルエラーとなり、正しくはe1.yとなる。
共変
Mapの場合、こんなふうになっている。
trait Map[A, +B] extends Iterable[(A, B)] with GenMap[A, B] with MapLike[A, B, Map[A, B]]
このvalueの型が+となっており、共変を表す。つまり以下はOKとなる。
var map1:Map[String, Parent] = Map("k1" -> new Parent()) var map2:Map[String, Child] = Map("k2" -> new Child()) map1 = map2
ただし、keyの型は共変ではないのでこれはダメ。コンパイルエラーとなる。
var map3:Map[Parent, String] = Map(new Parent() -> "v3") var map4:Map[Child, String] = Map(new Child() -> "v4") map3 = map4
反変
もし上記Mapのvalueの型に-がついて反変だったら、Map[String, Ancestor]のインスタンスがmap1に代入できる。