问题描述
我想知道是否可以通过这样的单例传递隐式参数
I wonder is it possible to pass implicit params through singletons like that
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
而受到影响,那么有什么办法可以做类似的事情吗?也许有一种方法可以为对象设置一个隐式,但要在其外部?
Bar.greetBar
doesn't affected by implicit value in main
, but I want it to be affected without passing implicit param to greetBar
, so is there any way to do something like that? Maybe there is a way to set an implicit for object but in outer of it?
推荐答案
您应在方法中添加隐式参数
You should add implicit parameter to the method
object Bar {
def greetBar(implicit greet: Greet /*= Greet("Hello")*/) = Foo.greet("Bar")
}
implicit val greet: Greet = Greet("Goodbye")
Bar.greetBar // Goodbye Bar
或将对象设为类,并向该类添加隐式参数
or make the object a class and add implicit parameter to the 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")
),则应取消注释.
I commented out default value /*= Greet("Hello")*/
. If you want greetBar
not to compile when there is no implicit in scope then you should keep it commented out. If you want behavior similar to greet
(i.e. Greet("Hello")
when there is no implicit in scope) then you should uncomment it.
请注意,如果在伴随对象中隐式定义了较低优先级,则可以避免重复默认值
Please notice that you can avoid repeating default value if you define lower-priority implicit in companion object
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
原则上,您可以使用宏注释 (但您不应该)
In principle, you can do this with a macro annotation (but you shouldn't)
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$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
//}
这篇关于通过多个对象传递隐式参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!