1. ホーム
  2. scala

[解決済み] Scalaの識別子 "implicitly "とは?

2022-04-22 02:09:22

質問

という名前の関数を見たことがあります。 implicitly Scala のサンプルで使用されています。これは何ですか、そしてどのように使用されていますか?

サンプルはこちら :

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 はどこでインプリシットを探すのですか?

どのように解決するのですか?

以下は、Delightly Simple Methodを使用する理由です。 implicitly .

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

Implicit Viewは、選択項目の接頭辞(例えば、以下のようなものを考えてみてください)があるときに起動することができます。 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

暗黙のViewは、以下のように、式がExpected Typeに適合しない場合にも発生します。

scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1

ここで、コンパイラはこの関数を探します。

scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>

コンテキストバウンドによって導入された暗黙のパラメータにアクセスする

暗黙のパラメータは、暗黙のViewよりも重要なScalaの機能だと言えるでしょう。これは型クラスパターンをサポートします。標準ライブラリはこれを数カ所で使っています。 scala.Ordering でどのように使用されているか、また SeqLike#sorted . 暗黙のパラメータは、Array マニフェストの受け渡しにも使用されます。 CanBuildFrom のインスタンスです。

Scala 2.8では、コンテキストバウンズと呼ばれる暗黙のパラメータの略記構文が使用できます。簡単に説明すると,型パラメタ 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)