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

时间:2017-05-17 07:26:51

标签: scala implicits

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

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

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

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

1 个答案:

答案 0 :(得分:5)

简短回答是"不,你不能"。

为什么呢?由于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 1}})。如果对象中有其他字段,则可以始终将它们放在类的伴随对象中,以最大限度地减少实例化时的开销。