为 Scala 的对象设置隐式实例变量

Setting implicit instance variable for Scala's object

我有一个带有一堆实用方法的 Scala 对象,每个方法都使用一个隐式方法参数 s

object MyObject {
 def a(implicit s:String) = ???
 def b(implicit s:String) = ???
 def c(implicit s:String) = ???
}

我不喜欢每个参数列表中都需要这个 implicit s:String。有没有办法只设置变量 s 一次(即第一次访问对象时)。对于 class 我会做这样的事情:

class MyClass(implicit s:String) {
 def a() = ???
 def b() = ???
 def c() = ???
}

简答为 "No you can't"。

为什么?因为 s 不是变量,而是参数。所以它不是在运行时的某个时间点设置的(比如,在第一次加入时),而是在编译时解析(因为它是隐式的)。

当您在代码的一部分中编写 MyObject.a 时,编译器将检查在当前范围内是否存在隐式 String 定义,并将该定义用于 s.

如果您随后在代码的另一部分使用 a,它将使用该范围内的隐式定义,这很可能会有所不同。

所有这些都是在编译时验证的,因此它与在运行时访问方法的时间无关(尽管访问它们可能会更改 s 的运行时值,如果你有可变隐式,应该避免)。

如果您总是希望对 s 使用相同的定义,为什么不直接将此定义放入您的对象中呢?或者将其作为隐式导入:

object MyObject {
  implicit def myImplicitString: String = ??? //first possibility
  import MyImplicits.stringImplicit //second possibility, if stringImplicit is indeed defined as implicit
}

最重要的是,如果您不想传递隐式参数,则需要将其包含在范围内,并且由于您的范围是 object,它必须始终相同。

但是,使用 class 有什么问题?它给你你想要的东西(避免重复隐式参数)而不改变你的调用(只需使用 new MyClass().a 而不是 MyObject.a,甚至 MyCaseClass().a 如果你将它定义为 case class).如果您的对象中有其他字段,您始终可以将它们放在 class 的伴随对象中,以最大限度地减少实例化时的开销。