Scala(或 Java)中泛型函数的特化

2024-05-12

是否可以在 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特征。首先警告:该功能存在一些问题,如果您尝试将其用于过于复杂的操作,则可能会损坏。但对于这个例子来说,它几乎是完美的。

The @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特征是通用的,但我们重写了我们想要的每个特定的原始类型(在本例中Byte and Int)并有适当的实施。专业化足够聪明,可以将这个显式版本与其通常用于专业化的隐藏版本联系起来。现在您已经有了自定义代码,但是如何使用它呢?这就是隐式值的用武之地(为了速度和清晰度,我这样做了):

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
  }
}

The A: BufferWriter符号意味着为了调用它write方法,你需要有一个隐式的BufferWriter[A]便利。我们已经为他们提供了 valsBufferWriters,所以我们应该设置。让我们看看这是否有效。

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您将看到正在使用适当的原始方法。

(请注意,如果您不使用专门化,此策略仍然有效,但必须将循环内的值装箱才能将数组复制出来。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala(或 Java)中泛型函数的特化 的相关文章

随机推荐

  • 如何使用 Spring MVC 和 Thymeleaf 添加静态文件

    我的问题是如何添加 CSS 和图像文件等静态文件 以便我可以使用它们 我正在使用 Spring MVC 和 Thymeleaf 我查看了有关此主题的各种帖子 但它们对我没有帮助 所以我才来问 根据这些帖子 我将 CSS 和图像文件放在res
  • 如何在 .htaccess 文件中创建一个包罗万象的处理程序?

    我想在 htaccess 文件末尾创建一条规则 捕获在此之前未能匹配的所有内容 我怎样才能做到这一点 附 我已经尝试过一切 实际上 我没有 但看起来确实如此 Update 有些人的回复是RewriteRule 或同等内容 这不行 它将匹配一
  • MUI v5:系统属性样式与 sx prop 之间是否存在性能差异?

    The 从 v4 迁移到 v5 https mui com guides migration v4 box指南指出 The Box系统 props 在 v5 中有一个可选的替代 API 使用sx支柱 你可以阅读本节 https mui co
  • 将原生 Twilio Android SDK 与 Flutter 集成

    我正在尝试使用 flutter 创建 IP 语音 VOIP 移动应用程序 我还没有看到 twilio 语音 api 的 flutter 插件的实现 所以我使用 MethodChannel 将我的应用程序与本机 android 语音 api
  • 中间件 API 的最佳实践是什么? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我们正在开发一个中间件 SDK 采用 C 和 Java 语言 供游戏开发人员 动画软件开发人员 阿凡达开
  • 如何在多字段中使用富文本(在 CQ5 对话框中)? (防止“this.el.dom未定义”错误)

    我创建了一个自定义组件 并尝试使用 RTE xtype richtext 在我的对话框中的多文件中 现在 当我尝试删除项目时 或者在关闭并重新打开对话框后添加另一个项目时 该对话框既不会关闭 也不会使用 确定 按钮保存数据 对话框 xml
  • Jquery:排除元素

    我有以下代码 document ready function a rel each function this qtip content text img class middle src i icon processing gif alt
  • 使用 Xcode 6 和(可能)cocoapods 生成错误

    在构建使用 cocoapods 和最新 Xcode 6 GM 版本的 iOS 项目时 我收到以下静态分析器错误 error error reading pic error no analyzer checkers are associate
  • 如何使用 JavaScript 压缩文件?

    有没有办法使用 JavaScript 来压缩文件 例如 在雅虎邮件中 当您选择下载电子邮件中的所有附件时 它会被压缩并下载到单个 zip 文件中 JavaScript 能够做到这一点吗 如果是这样 请提供一个编码示例 我发现这个图书馆叫js
  • git-svn --忽略路径

    我现在在 git svn 的 ignore paths 选项上挣扎了几个小时 试图从大型存储库中仅获取某些标签 我想在 dev 处开始获取 看起来像 gt svn ls http 192 168 0 2 svn repo corporati
  • SwiftUI ScrollView 只向一个方向滚动

    尝试使用视图作为列表行样式来创建自定义列表 以摆脱默认情况下列表中难看的分隔线 但是 一旦我将 ZStack 行放入滚动视图中 滚动视图就会在两个方向上滚动 而不仅仅是垂直滚动 这是内容视图 NavigationView ScrollVie
  • Python 正则表达式从文本中提取域

    我有以下正则表达式 r a zA Z0 9 a zA Z0 9 61 a zA Z0 9 a zA Z 2 6 当我将其应用于文本字符串时 比方说 这是 www website1 com 这是 website2 com 我得到 www we
  • 通用 scala 函数,其输入是变量数量的函数

    我想定义一个函数f需要另一个函数g 我们需要g采取采取n双打 对于某些固定n 并返回一个 Double 函数调用f g 应该返回具体值n 例如 f Math max 2因为 Math sin 具有类型 Double Double gt Do
  • 在 iPhone 5 的横向模式下启动启动画面

    我们的通用应用程序仅适用于横向模式 我们需要为 iPhone 4 和 iPhone 5 添加启动画面 对于 iPhone 5 的肖像 我们使用 email protected cdn cgi l email protection 如何为 i
  • fsockopen() 和 SSL 出错,“无法启用加密”

    我正在尝试连接到 Nominet EPP 测试台 但收到 无法启用加密 的消息 这似乎是一个罕见的错误 没有记录的解决方案或原因 用行 socket fsockopen ssl testbed epp nominet org uk 700
  • R:install.packages 中出现错误:无法打开连接

    我试图安装 RINDSEL 包 但无法安装它 并且不断收到以下错误 install packages 中出错 无法打开连接 我从以下位置下载了该软件包 rindsel 1 0 2 zip 综合养殖平台 http old ibpdev net
  • 如何从 Windows 7 PC 上完全卸载 Python 2.7

    从这里安装了Python 2 7 https www python org downloads release python 279 https www python org downloads release python 279 然后我
  • jq Streaming - 过滤嵌套列表并保留全局结构

    在一个大型 json 文件中 我想从嵌套列表中删除一些元素 但保留文档的整体结构 我的示例将其输入为 但真实的输入足够大以要求流式传输 keep untouched keep this this list filter this keep
  • 来自多元 t 分布的样本 python

    我想知道Python中是否有一个从多元学生t分布中采样的函数 我有包含 14 个元素的均值向量 14x14 协方差矩阵和自由度 我想从这个 t 分布中采样一个向量 对于一维情况 我使用 stats t rvs df loc scale 并且
  • Scala(或 Java)中泛型函数的特化

    是否可以在 Scala 中专门化泛型函数 或类 例如 我想编写一个将数据写入 ByteBuffer 的通用函数 def writeData T buffer ByteBuffer data T buffer put data 但由于 put