我正在编写一组现有 java library的隐式 scala 包装类(以便我可以装饰该库使其更方便 scala 开发人员(。
作为一个琐碎的例子,假设 java 库(我无法修改(具有以下类:
public class Value<T> {
// Etc.
public void setValue(T newValue) {...}
public T getValue() {...}
}
现在,假设我想用 scala - 风格的获取器和固定器来装饰此课程。我可以使用以下隐性类来做到这一点:
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
}
(同意,这不是很好的代码,并且不是完全 functional 。我只是想演示一个简单的用例。(
不幸的是, scala 不允许implicit
类是顶级的,因此必须在package object
,object
,class
或trait
中定义它们,而不仅仅是package
。(我不知道为什么需要这种限制,但是我认为这是与隐式转换函数兼容。(
但是,我也从AnyVal
扩展了RichValue
,以使其成为 value class 。如果您不熟悉它们,它们允许 scala 编译器进行优化。具体而言,编译器并不总是需要创建RichValue
的实例,并且可以直接在 value Class 的构造器参数上操作。
换句话说,使用A scala隐式值类作为包装器,这很不错,这很不错。: - (
但是,对 value类的主要限制是不能在class
或trait
中定义它们;他们只能是package
S,package object
S或object
S的成员。(这是为了使他们不需要维护指向外部类实例的指针。(
an 隐式值类必须尊重这两组约束,因此只能在package object
或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
语句将所有内容带入范围。
是否有一种直接实现这一目标的方法,这不会牺牲这种方法的任何好处?
(例如,我知道,如果我放弃制作这些包装器 value class ,那么我可以在许多不同的 trait
s中定义它们 - 每个组件软件包一个 - 并拥有我的root package object
将所有这些扩展,通过单个进口将所有内容都纳入范围,但我不想为方便起见而牺牲性能。(
implicit final class RichValue[T](private val v: Value[T]) extends AnyVal
本质上是以下两个定义的语法糖
import scala.language.implicitConversions // or use a compiler flag
final class RichValue[T](private val v: Value[T]) extends AnyVal
@inline implicit def RichValue[T](v: Value[T]): RichValue[T] = new RichValue(v)
(您可能会看到,这就是为什么内隐类必须在特征,对象或类中:它们也具有匹配的def
(
没有什么需要这两个定义一起生活的。您可以将它们放入单独的对象:
object wrappedLibValues {
final class RichValue[T](private val v: Value[T]) extends AnyVal {
// lots of implementation code here
}
}
object implicits {
@inline implicit def RichValue[T](v: Value[T]): wrappedLibValues.RichValue[T] = new wrappedLibValues.RichValue(v)
}
或特征:
object wrappedLibValues {
final class RichValue[T](private val v: Value[T]) extends AnyVal {
// implementation here
}
trait Conversions {
@inline implicit def RichValue[T](v: Value[T]): RichValue[T] = new RichValue(v)
}
}
object implicits extends wrappedLibValues.Conversions