daybreaksnow's diary

私を私と呼びたい

[Scala]入門 型パラメータと暗黙の引数

以下の連載の8,9回目読んだ。
http://www.atmarkit.co.jp/ait/kw/scala.html

型パラメータ

Javaでいうジェネリクスみたいなもの。

準備

class Base
class Hoge extends Base
class Piyo extends Hoge
class Fuga

上限境界

Javaでいう<Foo extends Base>
Scalaの慣習として、型パラメータはAから始めるらしい。

class Foo[A <: Base]

new Foo[Hoge]
//Baseを継承していないのでエラー
//new Foo[Fuga]

下限境界

Javaでいう<Foo super Hoge>

class Foo[A >: Hoge]

new Foo[Hoge]
//Hogeの親クラスでないのでエラー
//new Foo[Piyo]

クラス定義☆

特定のクラス定義を持つクラスを指定できる。
ダックタイピングっぽい?面白そう。

class Foo[A <: {def hoge():Unit}]

class Bar{
 def hoge = println
}

new Foo[Bar]

抽象型

抽象クラス、抽象メソッドに加え、フィールドや型も抽象化できる。
いまいち使いどころが分からない。

abstract class Base{
  type SomeFoo //抽象型
  def show(foo:SomeFoo)
}

class Foo{
  def exec = println("Exec")
}

class Child extends Base{
  type SomeFoo = Foo //抽象型をFooに
  def show(foo:SomeFoo) = foo.exec
}

型パラメータと同じ型境界の設定ができる。
この例だと最初からFoo型にしておけばいい気がするが…

type someFoo <: Foo //someFoo extends Foo扱い

暗黙の型変換

implicitで型変換メソッドを指定すると勝手に呼んでくれる

implicit def intToString(i:Int):String = i.toString()

val str:String = 1

なお、stringToIntを定義すると、ambiguous(曖昧)と言われてエラーになる。
しかし val i:Int = "1" で暗黙的な型変換が行われるわけでもない。謎。

Note that implicit conversions are not applicable because they are ambiguous

標準クラスを自作クラスへと変換したいときに使う?valueOfの代わり?

暗黙の引数

引数の型に合わせた値をあらかじめ用意しておくと、デフォルト値のように働く。
使いどころが分からない。適当に使うと危険に思える。

 def hoge(implicit str:String) = println(str)

 //暗黙の引数がないのでエラー
 //hoge()
 implicit val hogege = "hoge"
 hoge //暗黙の引数を利用。hoge()だとコンパイルエラー
 hoge("piyo") //普通にも呼べる

可視境界

A <: Hogeの暗黙の型変換対応版。
暗黙の型変換でAとみなせるならOK

class X[A <% Hoge] 

関数の呼び出し制約

型パラメータによって、インスタンス化はできるが、特定の関数呼び出しを禁止する

class X[A]{
  def exec(implicit arg:A =:= Int) = println("exec")
}

val intx = new X[Int]
val strx = new X[String]
intx.exec
//コンパイルエラー
//strx.exex

上限境界extendsを表したいなら以下。AはIntを継承したもの。

def exec(implicit A <:< Int)