Übergeben Sie implizite Parameter durch mehrere Objekte
Ich frage mich, ob es möglich ist, implizite Parameter durch solche Singletons zu übergeben
case class Greet(g: String)
object Foo {
def greet(name: String)(implicit greet: Greet = Greet("Hello")) = println(greet.g + " " + name)
}
object Bar {
def greetBar = Foo.greet("Bar")
}
object Main {
def main(args: Array[String]): Unit = {
implicit val greet: Greet = Greet("Goodbye")
Foo.greet("Sunshine") // Goodbye Sunshine
Bar.greetBar // Hello Bar
}
}
Bar.greetBarwird nicht durch impliziten Wert in beeinflusst main, aber ich möchte, dass er beeinflusst wird, ohne implizite Parameter zu übergeben. Gibt greetBares also eine Möglichkeit, so etwas zu tun? Vielleicht gibt es eine Möglichkeit, ein implizites Objekt zu setzen, aber außerhalb davon?
Antworten
Sie sollten der Methode implizite Parameter hinzufügen
object Bar {
def greetBar(implicit greet: Greet /*= Greet("Hello")*/) = Foo.greet("Bar")
}
implicit val greet: Greet = Greet("Goodbye")
Bar.greetBar // Goodbye Bar
oder machen Sie das Objekt zu einer Klasse und fügen Sie der Klasse implizite Parameter hinzu
class Bar(implicit greet: Greet /*= Greet("Hello")*/) {
def greetBar = Foo.greet("Bar")
}
implicit val greet: Greet = Greet("Goodbye")
(new Bar).greetBar // Goodbye Bar
Ich habe den Standardwert auskommentiert /*= Greet("Hello")*/. Wenn Sie greetBarnicht kompilieren möchten , wenn der Gültigkeitsbereich nicht impliziert ist, sollten Sie ihn auskommentieren. Wenn Sie ein ähnliches Verhalten wünschen greet(dh Greet("Hello")wenn der Gültigkeitsbereich nicht impliziert ist), sollten Sie es auskommentieren.
Beachten Sie, dass Sie das Wiederholen des Standardwerts vermeiden können, wenn Sie eine implizite niedrigere Priorität im Begleitobjekt definieren
case class Greet(g: String)
object Greet {
implicit val lowPriorityGreet: Greet = Greet("Hello")
}
object Foo {
def greet(name: String)(implicit greet: Greet) = println(greet.g + " " + name)
}
object Bar {
def greetBar(implicit greet: Greet) = Foo.greet("Bar")
}
// class Bar(implicit greet: Greet) {
// def greetBar = Foo.greet("Bar")
// }
implicit val greet: Greet = Greet("Goodbye")
Foo.greet("Sunshine") // Goodbye Sunshine
Bar.greetBar // Goodbye Bar
// (new Bar).greetBar // Goodbye Bar
Siehe auch Wie wird eine Methode mit Implikationen mit einer anderen Methode in Scala umbrochen?
Ich möchte dies tun, um
Greetimplizit für alle Methoden in zu setzenBar
Im Prinzip können Sie dies mit einer Makroanmerkung tun (sollten Sie aber nicht)
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
@compileTimeOnly("enable macro annotations")
class greetAware extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro GreetAwareMacro.impl
}
object GreetAwareMacro {
def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
val greet = TermName(c.freshName("greet"))
val implicitGreet = q"""implicit val $greet: Greet = Greet("Hello")""" def isImplicit(param: Tree): Boolean = param match { case q"$mods val $_: $_ = $_" => mods.hasFlag(Flag.IMPLICIT) } annottees match { case q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" :: Nil => val body1 = body.map { case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => val paramss1 = if (paramss.nonEmpty && paramss.last.nonEmpty && isImplicit(paramss.last.head)) paramss.init :+ (paramss.last :+ implicitGreet) else paramss :+ List(implicitGreet) q"$mods def $tname[..$tparams](...$paramss1): $tpt = $expr" case notMethod => notMethod } q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body1 }"
}
}
}
Verwendung:
@greetAware
object Foo {
def greet(name: String) = println(implicitly[Greet].g + " " + name)
}
@greetAware
object Bar {
def greetBar = Foo.greet("Bar")
def xxx(i: Int) = ???
def yyy(i: Int)(implicit s: String) = ???
}
implicit val greet: Greet = Greet("Goodbye")
Foo.greet("Sunshine") // Goodbye Sunshine
Bar.greetBar // Goodbye Bar
//scalac: object Foo extends scala.AnyRef {
// def <init>() = {
// super.<init>();
// ()
// };
// def greet(name: String)(implicit greet$macro$1: Greet = Greet("Hello")) = println(implicitly[Greet].g.$plus(" ").$plus(name)) //} //scalac: object Bar extends scala.AnyRef { // def <init>() = { // super.<init>(); // () // }; // def greetBar(implicit greet$macro$2: Greet = Greet("Hello")) = Foo.greet("Bar"); // def xxx(i: Int)(implicit greet$macro$2: Greet = Greet("Hello")) = $qmark$qmark$qmark;
// def yyy(i: Int)(implicit s: String, greet$macro$2: Greet = Greet("Hello")) = $qmark$qmark$qmark
//}