Scalaの例で使用されるimplicitly
という名前の関数を見てきました。それは何で、どのように使用されますか?
ここの例 :
scala> sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
| implicit def stringImpl = new Foo[String] {
| def apply(list : List[String]) = println("String")
| }
| implicit def intImpl = new Foo[Int] {
| def apply(list : List[Int]) = println("Int")
| }
| } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit
scala> foo(1)
<console>:8: error: type mismatch;
found : Int(1)
required: List[?]
foo(1)
^
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:8: error: could not find implicit value for evidence parameter of type
Foo[Double]
foo(List(1.0))
^
implicitly[Foo[A]].apply(x)
はパラメーターでimplicitly
を呼び出すことを意味するとコンパイラーが考えるため、implicitly[Foo[A]](x)
を記述する必要があることに注意してください。
Scala REPLからオブジェクト/タイプ/などを調査する方法 および Scalaはどこで暗黙的を探しますか? も参照してください。
以下に、非常にシンプルなメソッドimplicitly
を使用する理由をいくつか示します。
暗黙的なビューは、選択の接頭辞に含まれる場合にトリガーできます(たとえば、the.prefix.selection(args)
にselection
に適用可能なメンバーargs
が含まれていない場合(args
with Implicit Views)。この場合、コンパイラは、現在のスコープまたは囲みスコープでローカルに定義され、継承またはインポートされた暗黙のメンバーを探します。これらは、そのthe.prefix
の型からselection
定義済み、または同等の暗黙的メソッド。
scala> 1.min(2) // Int doesn't have min defined, where did that come from?
res21: Int = 1
scala> implicitly[Int => { def min(i: Int): Any }]
res22: (Int) => AnyRef{def min(i: Int): Any} = <function1>
scala> res22(1) //
res23: AnyRef{def min(i: Int): Int} = 1
scala> .getClass
res24: Java.lang.Class[_] = class scala.runtime.RichInt
暗黙的なビューは、次のように、式が期待されるタイプに適合しない場合にもトリガーできます。
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1
ここで、コンパイラはこの関数を探します。
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
暗黙のパラメーターは、おそらく、暗黙のビューよりもScalaのより重要な機能です。型クラスパターンをサポートします。標準ライブラリはこれをいくつかの場所で使用します-scala.Ordering
およびSeqLike#sorted
での使用方法を参照してください。暗黙パラメーターは、配列マニフェストとCanBuildFrom
インスタンスを渡すためにも使用されます。
Scala 2.8では、Context Boundsと呼ばれる暗黙的なパラメーターの簡略構文を使用できます。簡単に言うと、タイプM[A]
の暗黙的なパラメーターを必要とするタイプパラメーターA
を持つメソッド:
def foo[A](implicit ma: M[A])
次のように書き換えることができます。
def foo[A: M]
しかし、暗黙のパラメーターを渡し、名前を付けないのはどういう点ですか?メソッドfoo
を実装するときに、これはどのように役立ちますか?
多くの場合、暗黙的なパラメータは直接参照される必要はなく、呼び出される別のメソッドへの暗黙的な引数としてトンネリングされます。必要な場合は、Context Boundを使用して簡潔なメソッドシグネチャを保持し、implicitly
を呼び出して値を具体化できます。
def foo[A: M] = {
val ma = implicitly[M[A]]
}
型クラスベースのアプローチを使用して、人物をきれいに表示するメソッドを呼び出しているとします。
trait Show[T] { def show(t: T): String }
object Show {
implicit def IntShow: Show[Int] = new Show[Int] { def show(i: Int) = i.toString }
implicit def StringShow: Show[String] = new Show[String] { def show(s: String) = s }
def ShoutyStringShow: Show[String] = new Show[String] { def show(s: String) = s.toUpperCase }
}
case class Person(name: String, age: Int)
object Person {
implicit def PersonShow(implicit si: Show[Int], ss: Show[String]): Show[Person] = new Show[Person] {
def show(p: Person) = "Person(name=" + ss.show(p.name) + ", age=" + si.show(p.age) + ")"
}
}
val p = Person("bob", 25)
implicitly[Show[Person]].show(p)
名前の出力方法を変更したい場合はどうしますか? PersonShow
を明示的に呼び出して、代替のShow[String]
を明示的に渡すことができますが、コンパイラーにShow[Int]
を渡してほしいです。
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)
Implicitly
はScala 2.8で利用可能で、 Predef で次のように定義されます:
def implicitly[T](implicit e: T): T = e
タイプT
の暗黙的なvalueが利用可能かどうかをチェックし、それを返すチェックによく使用されますそのような場合。
retroym's presentation の簡単な例:
scala> implicit val a = "test" // define an implicit value of type String
a: Java.lang.String = test
scala> val b = implicitly[String] // search for an implicit value of type String and assign it to b
b: String = test
scala> val c = implicitly[Int] // search for an implicit value of type Int and assign it to c
<console>:6: error: could not find implicit value for parameter e: Int
val c = implicitly[Int]
^
「釣りを教えて」という答えは、 Scaladoc nightlies で現在利用可能なアルファベットのメンバーインデックスを使用することです。パッケージ/クラスペインの上部にある文字(およびアルファベット以外の名前の場合は#
)は、その文字で始まるメンバー名(すべてのクラス全体)のインデックスへのリンクです。 I
を選択した場合、たとえば、implicitly
に1回出現するPredef
エントリがあり、そこからリンクからアクセスできます。