0

私は暗黙の変換を実験してきましたが、これらを使用する「enrich-my-libray」パターンについて十分に理解しています。基本的な暗黙の理解と暗黙の証拠の使用を組み合わせようとしました...しかし、以下の方法で示すように、私は何か重要なことを誤解しています:

import scala.language.implicitConversions

object Moo extends App {

  case class FooInt(i: Int)
  implicit def cvtInt(i: Int) : FooInt = FooInt(i)
  implicit def cvtFoo(f: FooInt) : Int = f.i

  class Pair[T, S](var first: T, var second: S) {
    def swap(implicit ev: T =:= S, ev2: S =:= T) {
      val temp = first
      first = second
      second = temp
    }

    def dump() = {
      println("first is " + first)
      println("second is " + second)
    }
  }

  val x  = new Pair(FooInt(200), 100)
  x.dump
  x.swap
  x.dump
}

上記の方法を実行すると、次のエラーが発生します。

    Error:(31, 5) Cannot prove that nodescala.Moo.FooInt =:= Int.
      x.swap
        ^

私のスコープ内の暗黙的な変換は、Int を FooInt に、またはその逆に変換できるという十分な「証拠」になると思っていたので、私は困惑しています。これについて私をまっすぐに設定してくれてありがとう!

アップデート:

以下のピーターの優れた答えに混乱しなかった後、APIで暗黙の証拠を使用したいという正当な理由の1つに電球がつきました。この質問に対する私自身の回答で詳しく説明します(以下も)。

4

3 に答える 3

5

=:=これらの 2 つの型の値には暗黙的な変換が存在しますが、2 つの型が等しいかどうか、FooIntおよび絶対に等しくないかどうかをチェックします。Int

CanConvertを に変換できる型クラスを作成しAますB

trait CanConvert[A, B] {
  def convert(a: A): B
}

変換する型クラス インスタンスを作成IntFooInt、その逆を行うことができます。

implicit val Int2FooInt = new CanConvert[Int, FooInt] {
  def convert(i: Int) = FooInt(i)
}

implicit val FooInt2Int = new CanConvert[FooInt, Int] {
  def convert(f: FooInt) = f.i
}

CanConvertこれで、関数で使用できますPair.swap:

class Pair[A, B](var a: A, var b: B) {
  def swap(implicit a2b: CanConvert[A, B], b2a: CanConvert[B, A]) {
    val temp = a
    a = b2a.convert(b)
    b = a2b.convert(temp)
  }

  override def toString = s"($a, $b)"

  def dump(): Unit = println(this)
}

次のように使用できます。

scala> val x = new Pair(FooInt(200), 100)
x: Pair[FooInt,Int] = (FooInt(200), 100)

scala> x.swap

scala> x.dump
(FooInt(100), 200)
于 2015-08-30T10:47:34.550 に答える
0

この演習を行った後、API で暗黙の証拠サーブを使用する理由をよりよく理解できたと思います。

暗黙の証拠は、次の場合に非常に役立ちます。

  • パラメーターによって指定された型に作用するさまざまなメソッドを提供する型パラメーター化されたクラスがある。
  • これらのメソッドの 1 つ以上が、パラメーター化された型に追加の制約が配置された場合にのみ意味をなす場合。

したがって、元の質問で与えられた単純な API の場合:

class Pair[T, S](var first: T, var second: S) {
    def swap(implicit ev: T =:= S, ev2: S =:= T)  = ???
    def dump() =  ???
}

2 つのことを一緒に保持する型 Pair があり、いつでも dump() を呼び出して 2 つのことを調べることができます。また、特定の条件下では、ペアの最初と 2 番目のアイテムの位置を交換することもできます。そして、これらの条件は暗黙の証拠制約によって与えられます。


Programming in Scala book は、この手法が Scala コレクションで、特に Traversables の toMap メソッドでどのように使用されるかの良い例を示しています。

この本は、Map のコンストラクターが

キーと値のペア、つまり 2 つのタプルが引数として必要です。[Traversable] のペアのシーケンスがある場合、それらから Map を 1 つのステップで作成できたらいいと思いませんか? それが toMap の機能ですが、ジレンマがあります。シーケンスがペアのシーケンスでない場合、ユーザーが toMap を呼び出すことはできません。

したがって、すべての状況で使用できないメソッド [toMap] を持つタイプ [Traversable] の例があります...これは、コンパイラーが (暗黙の証拠を介して) 「証明」できる場合にのみ使用できます。 Traversable はペアです。

于 2015-08-30T20:58:28.197 に答える