我正在为现有的Java库编写一组隐式Scala包装器类(以便我可以装饰该库以使其对Scala开发人员更方便)。
举个简单的例子,假设Java库(我无法修改)有一个类,如下所示:
public class Value<T> {
// Etc.
public void setValue(T newValue) {...}
public T getValue() {...}
}
现在假设我想用Scala风格的 getter 和 setter 来装饰这个类。我可以使用以下隐式类来做到这一点:
final implicit class RichValue[T](private val v: Value[T])
extends AnyVal {
// Etc.
def value: T = v.getValue
def value_=(newValue: T): Unit = v.setValue(newValue)
}
该implicit
关键字告诉Scala编译器它可以将 的实例隐式转换Value
为 的实例RichValue
(前提是后者在范围内)。所以现在我可以将其中定义的方法应用RichValue
到Value
. 例如:
def increment(v: Value[Int]): Unit = {
v.value = v.value + 1
}
(同意,这不是很好的代码,也不完全是功能性的。我只是想演示一个简单的用例。)
不幸的是,Scala不允许implicit
类是顶级的,因此它们必须在 a 、 或 中定义package object
,而object
不仅仅是在 a 中。(我不知道为什么这个限制是必要的,但我认为它是为了与隐式转换函数兼容。)class
trait
package
但是,我也在扩展RichValue
fromAnyVal
以使其成为value class。如果您不熟悉它们,它们允许Scala编译器进行分配优化。具体来说,编译器并不总是需要创建 的实例RichValue
,并且可以直接对值类的构造函数参数进行操作。
换句话说,使用Scala 隐式值类作为包装器几乎没有性能开销,这很好。:-)
但是,值类的一个主要限制是它们不能在 aclass
或 a中定义trait
;它们只能是package
s、package object
s 或object
s 的成员。(这样他们就不需要维护指向外部类实例的指针。)
隐式值类必须遵守两组约束,因此它只能在 apackage object
或 an中定义object
。
这就是问题所在。我要包装的库包含具有大量类和接口的深层包层次结构。理想情况下,我希望能够使用单个import
语句导入我的包装类,例如:
import mylib.implicits._
使使用它们尽可能简单。
我目前看到的实现这一点的唯一方法是将所有隐式值类定义放在单个源文件中
的单个package object
(或)中:object
package mylib
package object implicits {
implicit final class RichValue[T](private val v: Value[T])
extends AnyVal {
// ...
}
// Etc. with hundreds of other such classes.
}
然而,这远非理想,我更愿意镜像目标库的包结构,但仍然通过单个import
语句将所有内容纳入范围。
有没有一种直接的方法来实现这一点,而不会牺牲这种方法的任何好处?
(例如,我知道如果我放弃使这些包装器值类,那么我可以在许多不同的 s 中定义它们trait
- 每个组件包一个 - 并让我的根package object
扩展所有这些,通过单个将所有内容带入范围导入,但我不想为了方便而牺牲性能。)