Build and use custom scala-library to extend primitive datatypes
对于研究原型,我希望能够使用其他字段扩展原始Scala数据类型(例如Double)。这是不可能的,因为scala.Double和scala.runtime.RichDouble被声明为final。
这是我尝试过的:
克隆scala存储库
从文件src/library/scala/runtime/RichDouble.scala
中的类scala.runtime.RichDouble中删除final修饰符
使用ant编译Scala:ant build-opt
创建一个扩展RichDouble:
的自定义类
$ echo"class MyDouble extends scala.runtime.RichDouble {}" > MyDouble.scala
使用自定义编译的scala编译MyDouble.scala:
$ build/pack/bin/scalac MyDouble.scala
但是,这将导致以下错误:
MyDouble.scala:1: error: illegal inheritance from final class RichDouble class
与strace一起运行时,确实正在加载自定义编译的scala-library.jar:
1 2
| $ strace -f ./build/pack/bin/scalac MyDouble.scala 2>&1 | grep scala-library
stat("/my/custom/dir/scala/build/pack/lib/scala-library.jar", {st_mode=S_IFREG|0664, st_size=5682113, ...}) = 0 |
我想念什么?即使删除了修饰符,为什么类RichDouble仍报告为final?
我试图做的事是不可能的。诸如Double之类的原始类型被实现为值类,它们隐式地为final。因此,不能扩展它们是它们的基本限制之一。
-
弗洛里安(Florian),一个显而易见的问题是,为什么您的"丰富"类型必须继承自标准值类?为什么不使用用于BigInt和其他类似类型的方法,而您的"丰富"类型实际上是实现某些特征/接口(例如Number)的常用类呢?
-
嘿,那是一个好点,我没有提到这一点:我正在与实际上使用RichDouble等的Spark框架集成。我想避免修改现有代码库的大部分内容。
-
好吧,我认为您当时不走运。我认为出于性能原因,Spark使用标准值类型。对于像Float或Double这样的类型,可以保证仅使用一条ASM指令即可解释所有标准操作,而不是通过接口调用更昂贵的某些方法。
您可以看一下隐式类:它们是为扩展封闭类而设计的。
1 2 3 4 5
| implicit class MyDouble (d : Double ) {
def myNewFeature () = println ("MyDouble is $d")
}
val d1 = new Double (42) // just instantiate a Double
d1. myNewFeature() // scala will do implicit conversion |
- 我知道隐式类。但是,它们不允许我添加一个新字段,该字段也将在对象序列化后进行序列化。