通过多个对象传递隐式参数
Pass implicit parameter through multiple objects
我想知道是否可以像那样通过单例传递隐式参数
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.greetBar
不受 main
中隐式值的影响,但我希望它在不将隐式参数传递给 greetBar
的情况下受到影响,所以有什么办法可以做某事像那样?也许有一种方法可以为对象设置隐式但在它的外部?
您应该向方法添加隐式参数
object Bar {
def greetBar(implicit greet: Greet /*= Greet("Hello")*/) = Foo.greet("Bar")
}
implicit val greet: Greet = Greet("Goodbye")
Bar.greetBar // Goodbye Bar
或者使对象成为 class 并将隐式参数添加到 class
class Bar(implicit greet: Greet /*= Greet("Hello")*/) {
def greetBar = Foo.greet("Bar")
}
implicit val greet: Greet = Greet("Goodbye")
(new Bar).greetBar // Goodbye Bar
我注释掉了默认值/*= Greet("Hello")*/
。如果您希望 greetBar
在范围内没有隐式时不编译,那么您应该将其注释掉。如果你想要类似于 greet
的行为(即 Greet("Hello")
当范围内没有隐含时)那么你应该取消注释它。
请注意,如果在伴生对象中定义 lower-priority 隐式
,则可以避免重复默认值
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
另请参阅
I want to do this to set Greet
implict for all methods in Bar
原则上,您可以使用 macro annotation(但您不应该这样做)
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 }"
}
}
}
用法:
@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: 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: Greet = Greet("Hello")) = Foo.greet("Bar");
// def xxx(i: Int)(implicit greet$macro: Greet = Greet("Hello")) = $qmark$qmark$qmark;
// def yyy(i: Int)(implicit s: String, greet$macro: Greet = Greet("Hello")) = $qmark$qmark$qmark
//}
我想知道是否可以像那样通过单例传递隐式参数
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.greetBar
不受 main
中隐式值的影响,但我希望它在不将隐式参数传递给 greetBar
的情况下受到影响,所以有什么办法可以做某事像那样?也许有一种方法可以为对象设置隐式但在它的外部?
您应该向方法添加隐式参数
object Bar {
def greetBar(implicit greet: Greet /*= Greet("Hello")*/) = Foo.greet("Bar")
}
implicit val greet: Greet = Greet("Goodbye")
Bar.greetBar // Goodbye Bar
或者使对象成为 class 并将隐式参数添加到 class
class Bar(implicit greet: Greet /*= Greet("Hello")*/) {
def greetBar = Foo.greet("Bar")
}
implicit val greet: Greet = Greet("Goodbye")
(new Bar).greetBar // Goodbye Bar
我注释掉了默认值/*= Greet("Hello")*/
。如果您希望 greetBar
在范围内没有隐式时不编译,那么您应该将其注释掉。如果你想要类似于 greet
的行为(即 Greet("Hello")
当范围内没有隐含时)那么你应该取消注释它。
请注意,如果在伴生对象中定义 lower-priority 隐式
,则可以避免重复默认值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
另请参阅
I want to do this to set
Greet
implict for all methods inBar
原则上,您可以使用 macro annotation(但您不应该这样做)
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 }"
}
}
}
用法:
@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: 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: Greet = Greet("Hello")) = Foo.greet("Bar");
// def xxx(i: Int)(implicit greet$macro: Greet = Greet("Hello")) = $qmark$qmark$qmark;
// def yyy(i: Int)(implicit s: String, greet$macro: Greet = Greet("Hello")) = $qmark$qmark$qmark
//}