web-dev-qa-db-ja.com

「暗黙的に」Scala識別子とは何ですか?

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はどこで暗黙的を探しますか? も参照してください。

160
oluies

以下に、非常にシンプルなメソッド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)
196
retronym

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]
                         ^
196
oluies

「釣りを教えて」という答えは、 Scaladoc nightlies で現在利用可能なアルファベットのメンバーインデックスを使用することです。パッケージ/クラスペインの上部にある文字(およびアルファベット以外の名前の場合は#)は、その文字で始まるメンバー名(すべてのクラス全体)のインデックスへのリンクです。 Iを選択した場合、たとえば、implicitlyに1回出現するPredefエントリがあり、そこからリンクからアクセスできます。

1
Randall Schulz