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


169

implicitlyScalaの例で使用されているという名前の関数を見てきました。それは何ですか、それはどのように使用されますか?

ここに例

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[Foo[A]](x)して呼び出すことを意味していると考えているため、 作成する必要があることに注意しimplicitlyてください。

オブジェクト/タイプ/その他を調査する方法も参照してくださいScala REPLから?そして、Scalaは暗黙的にどこを探しますか?

回答:


206

ここに、とても簡単な方法を使用するいくつかの理由がありますimplicitly

暗黙的ビューを理解/トラブルシューティングするには

暗黙ビューは、選択のプレフィックスに適用できるthe.prefix.selection(args)メンバーselectionが含まれていない場合(たとえば、暗黙ビューでargs変換しようとした後でも)トリガーできますargs。この場合、コンパイラーはローカルで定義された暗黙メンバーを探します継承またはインポートされた現在のスコープまたは包含スコープ内で、そのタイプから、定義さ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と呼ばれる暗黙のパラメーターの省略構文を使用できます。簡単に言うと、型Aの暗黙的なパラメーターを必要とする型パラメーターを持つメソッドM[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)

2
scala> 1.min(2)res0:Int = 1 Scala 2.10.3ではエラーが発生します:scala>暗黙的に[Int => {def min(i:Int):Any}] <console>:8:エラー: Int => AnyRef {def min(i:Int):Any}から使用できる暗黙のビューはありません。implicitly [Int => {def min(i:Int):Any}]
jhegedus

この回答は最新バージョンに更新されます。
emeth 2014年

1
implicitly [Int => AnyVal {def min(i:Int):Int}]が機能します。答えを修正する必要があります。
Malkaviano

212

ImplicitlyScala 2.8で利用可能であり、Predefでは次のように定義されています。

def implicitly[T](implicit e: T): T = e

通常、typeの暗黙的なTが使用可能かどうか確認し、そうである場合はそれを返すために使用されます

レトロニムのプレゼンテーションの簡単な例:

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

6
このメソッドは厳密にはチェックしません。暗黙の値が利用できない場合はコンパイルエラーが発生し、暗黙の値がある場合はそれを取得するようです。なぜこれを使いたいのか、もう少し詳しく説明してもらえますか
davetron5000

17
implicitly[Ordering[(Int, String)]].compare( (1, "b"), (1, "a") )、特にContext Boundによって導入された暗黙のパラメータを取得する場合:def foo[A: Ordering](a1: A, a2: A) = implicitly[Ordering[A]].compare(a1, a2)
retronym

1
上記のビデオリンクでレトロニムの議論を見るには、13:50までスキップしてください。
chaotic3quilibrium 2015年

-2

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


46
もちろん、これらのscaladocsは暗黙的に何も言わないので、ドキュメントとしては数えられません。誰かがそれらのドキュメントだけからその方法が何をするかをどのように理解するでしょうか?Scalaのドキュメントにはいつもがっかりしています。暗黙のようなメソッドの動作は明白とはほど遠く、それらに関するドキュメントは存在しないよりもかろうじて優れています。Stack Overflowを神に感謝します。/ end rant
ジェフ


4
型シグネチャはこれをかなりよく文書化します。
レトロネーム10:19

21
implicitScalaの重要な言語機能であり、適切に説明する価値があるようです。型シグネチャの数だけを詳述しているドキュメントは、本物の答えというより、知的自己満足のように思えます。OPによって尋ねられた特定の質問を参照してください-それは何であり、どのように使用されますか?これでも、実際のリンクを提供していない夜間のドキュメントでも回答されません。scala-lang.org/files/archive/nightly/docs/library/… これは何も教えていません。正規のドキュメントの例については、Niklaus WirthまたはTurbo Pascalを参照してください。-1
トーマスW

3
implicitimplicitly関連していますが、まったく異なります。implicitキーワードは、言語の一部です。implicitly標準ライブラリのプレーンなScalaコードで定義されています。オンラインドキュメントにはソースリンクが含まれているので、質問者にそれらのドキュメントとリンクされたソースを参照させるのが依然として最善であると私は信じています。
Randall Schulz、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.