Pasar parámetros implícitos a través de múltiples objetos
Me pregunto si es posible pasar parámetros implícitos a través de singletons como ese
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.greetBarno se ve afectado por el valor implícito en main, pero quiero que se vea afectado sin pasar un parámetro implícito a greetBar, entonces, ¿hay alguna forma de hacer algo así? ¿Quizás hay una manera de establecer un objeto implícito para pero fuera de él?
Respuestas
Debes agregar un parámetro implícito al método
object Bar {
def greetBar(implicit greet: Greet /*= Greet("Hello")*/) = Foo.greet("Bar")
}
implicit val greet: Greet = Greet("Goodbye")
Bar.greetBar // Goodbye Bar
o hacer del objeto una clase y agregar un parámetro implícito a la clase
class Bar(implicit greet: Greet /*= Greet("Hello")*/) {
def greetBar = Foo.greet("Bar")
}
implicit val greet: Greet = Greet("Goodbye")
(new Bar).greetBar // Goodbye Bar
Comenté el valor predeterminado /*= Greet("Hello")*/. Si no desea greetBarcompilar cuando no hay un alcance implícito, debe mantenerlo comentado. Si desea un comportamiento similar a greet(es decir, Greet("Hello")cuando no hay un alcance implícito), debe descomentarlo.
Tenga en cuenta que puede evitar la repetición del valor predeterminado si define una prioridad más baja implícita en el objeto complementario
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
Consulte también ¿Cómo envolver un método que tiene implicaciones con otro método en Scala?
Quiero hacer esto para establecer
Greetimplict para todos los métodos enBar
En principio, puede hacer esto con una macro anotación (pero no debería)
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 }"
}
}
}
Uso:
@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
//}