我想知道是否有可能通过像这样的singleton传递隐式参数
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
的情况下受到影响,所以有什么方法可以做到这一点吗?也许有一种方法可以设置一个隐含的for对象,但在它的外部?
您应该向方法添加隐式参数
object Bar {
def greetBar(implicit greet: Greet /*= Greet("Hello")*/) = Foo.greet("Bar")
}
implicit val greet: Greet = Greet("Goodbye")
Bar.greetBar // Goodbye Bar
或者使对象成为类,并向类添加隐式参数
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")
(,则应该取消注释。
请注意,如果您在伴随对象中定义了隐含的较低优先级,则可以避免重复默认值
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
另请参阅如何在Scala中用另一个方法包装一个有隐词的方法?
我想为
Bar
中的所有方法设置Greet
implict
原则上,您可以使用宏注释(但不应该(来完成此操作
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
//}