隐含价值类的优雅分组



我正在编写一组现有 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 objectobjectclasstrait中定义它们,而不仅仅是package。(我不知道为什么需要这种限制,但是我认为这是与隐式转换函数兼容。(

但是,我也从AnyVal扩展了RichValue,以使其成为 value class 。如果您不熟悉它们,它们允许 scala 编译器进行优化。具体而言,编译器并不总是需要创建RichValue的实例,并且可以直接在 value Class 的构造器参数上操作。

换句话说,使用A scala隐式值类作为包装器,这很不错,这很不错。: - (

但是,对 value类的主要限制是不能在classtrait中定义它们;他们只能是package S,package object S或object S的成员。(这是为了使他们不需要维护指向外部类实例的指针。(

an 隐式值类必须尊重这两组约束,因此只能在package objectobject中定义。

这就是问题。我包装的库包含包装的深层层次结构,这些包装包含大量的类和界面。理想情况下,我希望能够用单个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

相关内容

  • 没有找到相关文章

最新更新