Scala:将多个函数转换为单个泛型函数?

Scala:将多个函数转换为单个泛型函数?,scala,generics,Scala,Generics,我有以下函数系列(显示了其中两个),我希望将其作为单个通用函数实现: case类RichSeqInt(seq:seq[Int])扩展了AnyVal{ def toByteArray:数组[字节]={ val buffer=字节缓冲分配(4*序列长度) buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN) 序号foreach(缓冲区putInt) buffer.array() } } 案例类richseklong(seq:seq[Long])扩展了AnyVa

我有以下函数系列(显示了其中两个),我希望将其作为单个通用函数实现:

case类RichSeqInt(seq:seq[Int])扩展了AnyVal{
def toByteArray:数组[字节]={
val buffer=字节缓冲分配(4*序列长度)
buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN)
序号foreach(缓冲区putInt)
buffer.array()
}
}
案例类richseklong(seq:seq[Long])扩展了AnyVal{
def toByteArray:数组[字节]={
val buffer=字节缓冲分配(8*序列长度)
buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN)
序号foreach(缓冲区putLong)
buffer.array()
}
}
我不知道如何获得基本对象的大小,然后如何将其放入缓冲区,尽管这似乎是可行的


这是可能的吗?

您可以使用类型类,但您将失去拥有类型值的可能性,因为此模式需要使用隐式参数:

import java.nio.{ByteBuffer, ByteOrder}

trait Bufferable[A] {
  def size: Int
  def put(a: A, buffer: ByteBuffer): Unit
}

implicit val intBufferable: Bufferable[Int] =
  new Bufferable[Int] {
    override val size = java.lang.Integer.SIZE / 8
    def put(n: Int, buffer: ByteBuffer): Unit = buffer.putInt(n)
  }

implicit val longBufferable: Bufferable[Long] =
  new Bufferable[Long] {
    override val size = java.lang.Long.SIZE / 8
    def put(n: Long, buffer: ByteBuffer): Unit = buffer.putLong(n)
  }

final case class RichSeq[A](seq: Seq[A])(implicit buf: Bufferable[A]) {
  def toByteArray: Array[Byte] = {
    val buffer = ByteBuffer.allocate(buf.size * seq.length)
    buffer.order(ByteOrder.LITTLE_ENDIAN)
    seq.foreach(buf.put(_, buffer))
    buffer.array()
  }
}

RichSeq(Vector(1, 2, 3)).toByteArray.size // evaluates to 12
RichSeq(Vector(1L, 2L, 3L)).toByteArray.size // evaluates to 24
您可以使用此代码

如果你可以,你可能想考虑有一个简单的帮手,这样你就可以避免不必要的分配:

object SeqUtils {
  def toByteArray[A](seq: Seq[A])(implicit buf: Bufferable[A]): Array[Byte] = {
    val buffer = ByteBuffer.allocate(buf.size * seq.length)
    buffer.order(ByteOrder.LITTLE_ENDIAN)
    seq.foreach(buf.put(_, buffer))
    buffer.array()
  }
}

SeqUtils.toByteArray(Vector(1, 2, 3)).size
SeqUtils.toByteArray(Vector(1L, 2L, 3L)).size
修改后的示例更进一步


如果您想了解更多有关类型类的信息,我通常会建议您在网上提供大量的资料。

这应该可以,但我不确定是否会这样做:

  def toByteArray[A: Manifest](seq: Seq[A]): Array[Byte] = seq match {
    case i: Seq[Int] if manifest <:< manifest[Int] => {
      val buffer = ByteBuffer.allocate(4 * seq.length)
      buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN)
      seq.foreach{x => buffer.putInt(x.asInstanceOf[Int])}
      buffer.array()
    }
    case l: Seq[Long] if manifest <:< manifest[Long] => {
      val buffer = ByteBuffer.allocate(8 * seq.length)
      buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN)
      seq.foreach{x => buffer.putLong(x.asInstanceOf[Long])}
      buffer.array()    
    }
    case _ => throw new java.lang.UnsupportedOperationException
  }
def toByteArray[A:Manifest](seq:seq[A]):数组[Byte]=seq匹配{
案例一:如果有舱单,则为Seq[Int]{
val buffer=字节缓冲分配(4*序列长度)
buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN)
seq.foreach{x=>buffer.putInt(x.asInstanceOf[Int])}
buffer.array()
}
案例一:如果舱单,则为Seq[Long]{
val buffer=字节缓冲分配(8*序列长度)
buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN)
seq.foreach{x=>buffer.putLong(x.asInstanceOf[Long]))
buffer.array()
}
case=>抛出新java.lang.UnsupportedOperationException
}

当然,这可以以更干净的方式编写,并且可以提取某些公共部分。还有一个提示,
a移动
(隐式buf:Bufferable[a]
到该方法,然后恢复anyval。另外,最好将这些隐式移到typeclass的伴生对象。谢谢。我已经让它工作了,但是我应该将隐式放在哪里以便自动找到它们呢?我在Sekutils和RichSeq中都试过了,但运气不佳。我目前正在显式导入它们。@RandomB这会将他们移动到Bufferable的伴生对象。当然,居住在那里对他们来说非常有意义。请不要在项目中使用Bufferable这个名称,我相信你会找到一个更好的名称。注意:完成考虑:注意
上的
.lenght
调用复杂性可以是线性的(就像
列表的情况一样,它们是
Seq
的默认实现——使用工厂方法)。
案例一:Seq[Int]
不起作用,它与
案例一:Seq[\u]
相同,它只在
的情况下起作用,如果
的话。清单有点粗糙,不常见(通常使用ClassTag)这根本不会减少样板文件。
case i:Seq[Int]if-manifest
肯定有效。我同意这有点黑客,但它仍然是一个解决方案。
ClassTag
是另一种方式,我同意。是的,它对if有效,但会产生擦除警告,这相当于
case i:Seq如果舱单