Scala(或Java)中通用函数的专业化
是否有可能在Scala中专门化通用函数(或类)?例如,我想编写一个将数据写入ByteBuffer的通用函数:
def writeData[T](buffer: ByteBuffer,data: T) = buffer.put(data) 但是因为put方法只需要一个字节并将其放入缓冲区,我需要专门为Ints和Longs如下: def writeData[Int](buffer: ByteBuffer,data: Int) = buffer.putInt(data) def writeData[Long](buffer: ByteBuffer,data: Long) = buffer.putLong(data) 并且它不会编译。当然,我可以改为分别写3个不同的函数writeByte,writeInt和writeLong,但是我们假设有一个数组的另一个函数: def writeArray[T](buffer: ByteBuffer,array: Array[T]) { for (elem <- array) writeData(buffer,elem) } 并且这将不工作没有专门的writeData函数:我将不得不部署另一组函数writeByteArray,writeIntArray,writeLongArray。不得不处理情况这种方式每当我需要使用类型相关的写功能不是很酷。我做了一些研究,一个可能的解决方法是测试参数的类型: def writeArray[T](buffer: ByteBuffer,array: Array[T]) { if (array.isInstanceOf[Array[Byte]]) for (elem <- array) writeByte(buffer,elem) else if (array.isInstanceOf[Array[Int]]) for (elem <- array) writeInt(buffer,elem) ... } 这可能工作,但它的效率较低,因为类型检查是在运行时完成的不像专门的功能版本。 所以我的问题是,什么是最理想和最喜欢的方式来解决这种问题在Scala或Java?我感谢您的帮助提前! 解决方法
如果你能拥有一个紧凑和有效的解决方案不是很好吗?原来,你可以,给予Scala的@specialized功能。首先一个警告:功能有点bug,如果你尝试使用它的东西太复杂,可能会中断。但对于这种情况,它几乎完美。
@specialized注释为每个基本类型创建单独的类和/或方法,然后每当编译器确定基本类型是什么时调用它而不是通用版本。唯一的缺点是它完全自动完成所有这一切 – 你不必填写自己的方法。这是一种耻辱,但你可以克服使用类型类的问题。 让我们看看一些代码: import java.nio.ByteBuffer trait BufferWriter[@specialized(Byte,Int) A]{ def write(b: ByteBuffer,a: A): Unit } class ByteWriter extends BufferWriter[Byte] { def write(b: ByteBuffer,a: Byte) { b.put(a) } } class IntWriter extends BufferWriter[Int] { def write(b: ByteBuffer,a: Int) { b.putInt(a) } } object BufferWriters { implicit val byteWriter = new ByteWriter implicit val intWriter = new IntWriter } 这给了我们一个BufferWriter trait,它是通用的,但是我们用适当的实现重写了我们想要的每个特定的原始类型(在这里是Byte和Int)。专业化是聪明的,以链接这个显式版本与隐藏的通常用于专业化的。所以你有你的自定义代码,但是如何使用它?这是隐式vals进来的地方(我这样做的速度和清晰度): import BufferWriters._ def write[@specialized(Byte,Int) A: BufferWriter](b: ByteBuffer,ar: Array[A]) { val writer = implicitly[BufferWriter[A]] var i = 0 while (i < ar.length) { writer.write(b,ar(i)) i += 1 } } A:BufferWriter符号意味着为了调用这个写方法,你需要一个隐式BufferWriter [A]。我们为它们提供了BufferWriter的val,所以我们应该设置。让我们看看这是否工作。 val b = ByteBuffer.allocate(6) write(b,Array[Byte](1,2)) write(b,Array[Int](0x03040506)) scala> b.array res3: Array[Byte] = Array(1,2,3,4,5,6) 如果你把这些东西放在一个文件中,并开始用javap -c -private探索类,你会看到正在使用适当的基本方法。 (注意,如果你没有使用专门化,这个策略仍然可以工作,但它必须在循环内的值复制数组)。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |