web-dev-qa-db-ja.com

Scala:1つの暗黙的なパラメーターを暗黙的に、もう1つを明示的に渡す。出来ますか?

関数を考えてみましょう:

def foo(implicit a:Int, b:String) = println(a,b)

ここで、暗黙のStringおよびIntimplicit val i1=1)スコープ内ですが、他を渡したいnot暗黙的Intval i2=2)明示的にfooに。

どうすればそれができますか?出来ますか?読んでくれてありがとう。

29
jhegedus

追加できるのは:

def foo(implicit a: Int, b: String) = println(a, b)
implicit val i1 = 1
implicit val s = ""
val i2 = 2
foo(i2, implicitly[String])
31
Peter Schmitz

メソッドに多くの暗黙的なパラメーターがある場合(私はプロジェクトにある場合があります)、それらの1つを明示的に指定し、他のパラメーターを暗黙的に解決させたい場合は、に示すように他のすべてのパラメーターにimplicitly私の他の答え。ただし、そのメソッドのシグネチャを変更したり、明示的なパラメーターがそのパラメーターリストの途中にある場合は、次の構成を使用してより読みやすいクライアントコードを作成できます。

いくつかのタイプとその暗黙のダミーオブジェクトがあるとします。

trait I1; implicit object I1 extends I1
trait I2; implicit object I2 extends I2
trait I3; implicit object I3 extends I3
trait I4; implicit object I4 extends I4
trait I5; implicit object I5 extends I5
trait I6; implicit object I6 extends I6

これで、これらの暗黙を使用するメソッドfoo1ができました。

def foo1(implicit i1: I1, i2: I2, i3: I3, i4: I4, i5: I5, i6: I6) {
  println(i1, i2, i3, i4, i5, i6)
}

ここで、i4: I4を明示的に指定することがよくあります。だからあなたは書く:

val i4 = new I4 {}
foo1(implicitly, implicitly, implicitly, i4, implicitly, implicitly)

醜い!
次のすべての暗黙のラッパー(メソッドfoo2の狭いスコープに配置し、名前を変更する必要があります)を使用します。

object Implicits {
  def apply(i4: I4)(implicit i1: I1, i2: I2, i3: I3, i5: I5, i6: I6) = new Implicits(i1, i2, i3, i4, i5, i6)
  implicit def applying(implicit i1: I1, i2: I2, i3: I3, i4: I4, i5: I5, i6: I6) = new Implicits(i1, i2, i3, i4, i5, i6)
}
class Implicits(val i1: I1, val i2: I2, val i3: I3, val i4: I4, val i5: I5, val i6: I6)

および関連するメソッドfoo2

def foo2(implicit implicits: Implicits) = {
  import implicits._
  println(i1, i2, i3, i4, i5, i6)
}

次のようにfoo2ではなくfoo1を呼び出すことができます。

locally {
  foo2 // using implicit dummy objects I1, ..., I6 from above
  // or with explicit I4:
  val i4 = new I4 {}
  foo2(Implicits(i4))
}
5
Peter Schmitz
  1. 明示的にfoo(i2, s1)を呼び出しますが、_implicit String_を使用するメリットを失います
  2. def foo1(a: Int)(implicit b: String)=foo(a,b)を定義し、foo1(i2)を呼び出します
4
Bruno Grieder

新しい内部スコープを作成し、その中に新しいimplicit valを定義できます。利点は、複数の関数呼び出しがある場合よりも、このようにして、すべての関数に対して暗黙的なものを1か所でオーバーライドできます。

def foo(implicit a:Int, b:String) = println(a,b).

implicit val i = 1
implicit val s = ""

foo // call with original implicits

{
  implicit val i = 2

  foo // call with a new Int implicit

  foo // call with a new Int implicit again

}

注:新しい暗黙の変数は元の変数と同じ変数名にする必要があります。そうしないと非表示になります。そうしないと、あいまいな暗黙の値に関するコンパイラエラーが発生します。

2
Suma

私はそれが古い質問であることを知っていますが、それでも興味深いかもしれません。これを行うための良い方法は、暗黙的にデフォルト値として使用することです。

scala> def foo(a: Int = implicitly[Int], b: String = implicitly[String]) = println(a,b)

scala> foo()
(10,boo)

scala> foo(50)
(50,boo)

scala> foo(b="bar")
(10,bar)
0
roterl