具有重复参数(可变参数)的磁铁模式

2024-04-18

是否可以使用磁铁图案 http://spray.io/blog/2012-12-13-the-magnet-pattern/与可变参数:

object Values {
  implicit def fromInt (x : Int ) = Values()
  implicit def fromInts(xs: Int*) = Values()
}
case class Values()

object Foo {  
  def bar(values: Values) {}
}

Foo.bar(0)
Foo.bar(1,2,3) // ! "error: too many arguments for method bar: (values: Values)Unit"

?


正如 gourlaysama 已经提到的,将 varargs 变成单个Product从语法上来说,就可以解决这个问题:

implicit def fromInts(t: Product) = Values()

这使得以下调用可以正常编译:

Foo.bar(1,2,3)

这是因为编译器自动将 3 个参数提升为Tuple3[Int, Int, Int]。这适用于任意数量的参数,最多可达 22 个。现在的问题是如何使其类型安全。因为它是Product.productIterator是在方法体内取回参数列表的唯一方法,但它返回一个Iterator[Any]。我们不能保证该方法只会被调用Ints。这应该不足为奇,因为我们实际上从未在签名中提到我们只想要Ints.

好的,所以无约束之间的主要区别Product可变参数列表的特点是在后一种情况下每个元素都具有相同的类型。我们可以使用类型类对其进行编码:

abstract sealed class IsVarArgsOf[P, E]
object IsVarArgsOf {
  implicit def Tuple2[E]: IsVarArgsOf[(E, E), E] = null
  implicit def Tuple3[E]: IsVarArgsOf[(E, E, E), E] = null
  implicit def Tuple4[E]: IsVarArgsOf[(E, E, E, E), E] = null
  implicit def Tuple5[E]: IsVarArgsOf[(E, E, E, E, E), E] = null
  implicit def Tuple6[E]: IsVarArgsOf[(E, E, E, E, E), E] = null
  // ... and so on... yes this is verbose, but can be done once for all
}

implicit class RichProduct[P]( val product: P )  {
  def args[E]( implicit evidence: P IsVarArgsOf E ): Iterator[E] = {
    // NOTE: by construction, those casts are safe and cannot fail
    product.asInstanceOf[Product].productIterator.asInstanceOf[Iterator[E]]
  }
}

case class Values( xs: Seq[Int] )
object Values {
  implicit def fromInt( x : Int ) = Values( Seq( x ) )
  implicit def fromInts[P]( xs: P )( implicit evidence: P IsVarArgsOf Int ) = Values( xs.args.toSeq )
}


object Foo {  
  def bar(values: Values) {}
}

Foo.bar(0)
Foo.bar(1,2,3)

我们改变了方法签名形式

implicit def fromInts(t: Product)

to:

implicit def fromInts[P]( xs: P )( implicit evidence: P IsVarArgsOf Int )

在方法体内,我们使用新方法args获取我们的 arg 列表。

请注意,如果我们尝试调用bar与一个不是元组的元组Ints,我们将得到一个编译错误,这使我们恢复了类型安全。


UPDATE:正如 0__ 所指出的,我的上述解决方案不能很好地适应数字加宽。换句话说,以下内容无法编译,尽管如果bar只需要 3Int参数:

Foo.bar(1:Short,2:Short,3:Short)
Foo.bar(1:Short,2:Byte,3:Int)

为了解决这个问题,我们需要做的就是修改IsVarArgsOf这样所有的隐式都允许 元组元素可转换为通用类型,而不是全部为同一类型:

abstract sealed class IsVarArgsOf[P, E]
object IsVarArgsOf {
  implicit def Tuple2[E,X1<%E,X2<%E]: IsVarArgsOf[(X1, X2), E] = null
  implicit def Tuple3[E,X1<%E,X2<%E,X3<%E]: IsVarArgsOf[(X1, X2, X3), E] = null
  implicit def Tuple4[E,X1<%E,X2<%E,X3<%E,X4<%E]: IsVarArgsOf[(X1, X2, X3, X4), E] = null
  // ... and so on ...
}

好吧,实际上我撒谎了,我们还没有结束。因为我们现在接受不同类型的元素(只要它们可以转换为通用类型,我们就不能将它们强制转换为预期类型(这会导致运行时强制转换错误),而是必须应用隐式转换。我们可以这样修改它:

abstract sealed class IsVarArgsOf[P, E] {
  def args( p: P ): Iterator[E]
}; object IsVarArgsOf {
  implicit def Tuple2[E,X1<%E,X2<%E] = new IsVarArgsOf[(X1, X2), E]{
    def args( p: (X1, X2) ) = Iterator[E](p._1, p._2)
  }
  implicit def Tuple3[E,X1<%E,X2<%E,X3<%E] = new IsVarArgsOf[(X1, X2, X3), E]{
    def args( p: (X1, X2, X3) ) = Iterator[E](p._1, p._2, p._3)
  }
  implicit def Tuple4[E,X1<%E,X2<%E,X3<%E,X4<%E] = new IsVarArgsOf[(X1, X2, X3, X4), E]{
    def args( p: (X1, X2, X3, X4) ) = Iterator[E](p._1, p._2, p._3, p._4)
  }
  // ... and so on ...
}
implicit class RichProduct[P]( val product: P ) {
  def args[E]( implicit isVarArg: P IsVarArgsOf E ): Iterator[E] = {
    isVarArg.args( product )
  }
}

这解决了数字加宽的问题,并且在混合不相关类型时我们仍然得到编译:

scala> Foo.bar(1,2,"three")
<console>:22: error: too many arguments for method bar: (values: Values)Unit
          Foo.bar(1,2,"three")
                 ^
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有重复参数(可变参数)的磁铁模式 的相关文章

随机推荐

  • gdb 输入文件中的十六进制值

    我正在尝试通过使用 gdb 内的 run 我可以成功地溢出程序 但在将十六进制值附加到字符串时遇到问题 我尝试过引用 将 mem addr 的值转换为 ascii 以及各种转义尝试 但没有成功 输入文件示例 AAAA x42 在上面的示例中
  • 监控 REST API 的最佳方式是什么? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我创建了一个基于 RESTful 模式的 API 我想知道监视它的最佳方法是什么 我可以以某种方式收集每个请求的统计信息以及我可以监控
  • jsfiddle问题[重复]

    这个问题在这里已经有答案了 我无法让这个极其简单的 jsfiddle 工作 它只是应该在单击按钮时提醒测试 我在这里缺少什么 http jsfiddle net u9nG6 2 http jsfiddle net u9nG6 2 您必须将加
  • CSS 滤色器叠加

    我正在尝试在图像上创建颜色叠加层 就像在这个应用程序中一样 图像上的绿色叠加层 https i stack imgur com FdgdA png https i stack imgur com FdgdA png 对我来说 他们看起来并不
  • Word 2007 VBA:ActiveDocument.CustomXMLParts

    In 本教程 https learn microsoft com en us archive blogs erikaehrli data driven document generation with word 2007 and the o
  • 从 ViewPager 中删除由 FragmentStatePagerAdapter 填充的所有片段

    我有一个 ViewPager 我使用 FragmentStatePagerAdapter 填充片段 代表 arrayListOfObjects 中的对象 一切正常 mMyFragmentPagerAdapter new fragmentAd
  • 更少的 css 编译器。无法使用变暗属性

    我正在开发一个项目 使用 LESS 作为我的 CSS 编译器 我已经有一个完全工作的循环 可以正确设置背景颜色 我的问题是这样的 使用我当前的代码 当我尝试使用 darken 属性时 编译结果是这样的 SyntaxError 错误评估函数d
  • 我应该使用哪个功能接口?

    我正在学习编写一些 lambda 表示形式功能接口 https docs oracle com en java javase 11 docs api java base java lang FunctionalInterface html
  • UIView 的 viewDidLoad 吗?

    是什么viewDidLoad for UIView 我有一个UIView与 xib 一起 我想在加载时隐藏它的子视图之一 我尝试使用这个 id initWithCoder NSCoder aDecoder theView hidden YE
  • 使用 Json.NET 反序列化空数组

    我有一个使用 Json NET v7 0 1 的 C 应用程序 作为 REST 调用的结果 我以以下形式返回一些 JSON messages phoneNumber 123 456 7890 smsText abcd1234 phoneNu
  • 如何使用 Jquery 更改辅助样式表?

    我的网站上有我的 base css 和 red css 我喜欢在按下某个按钮时将 red css 更改为 blue css 而不丢失 base css 如何执行此操作 我试过这个
  • Dataframe 根据其他列创建新列

    我有一个数据框 df lt data frame a c 1 2 3 4 5 b c 1 20 3 4 50 df a b 1 1 1 2 2 20 3 3 3 4 4 4 5 5 50 我想根据现有列创建一个新列 像这样的事情 if df
  • for 语句后的大括号

    我是新手 编写一个代码来打印从 1 到 10 的数字之和 事情是这样的 for a 1 a lt 10 a sum a cout lt
  • excel函数“R中决策函数的搜索

    我有一个问题 R中是否可以实现excel函数 决策搜索 R中有没有函数或者需要在R中创建一个脚本 需要结合以下方程来求解X值得到 1 126 作为结果 1 126 X X 0 2 EXP X 0 2 1 您可以使用以下方法找到该方程的解un
  • .vimrc 控制键映射不起作用

    我的 vimrc 中有以下映射 用于映射控制键 1 2 3 用于切换选项卡 我在 ubuntu 11 10 中使用 gnome 终端 控制键映射似乎不起作用 谁能告诉我我做错了什么 VIM Vi 改进版 7 3 154 map
  • 如何在不关闭vim的情况下重置vim的设置(包括插件,.vimrc文件)?

    我已经使用 vim 两年了 我使用 pathogen 进行插件管理 我在寻找 一种在不关闭 vim 的情况下重置所有 vim 设置 包括插件 vimrc 文件 的方法 是 有什么想法吗 PS 在某些情况下 重新加载 vimrc 与重新打开
  • Android 在其他设备上共享显示

    我正在努力与通过 WiFi 连接的多个表 全部有根 共享平板电脑显示屏 我正在使用以下方法 全部在一个线程内 1 我截屏 Process sh Runtime getRuntime exec su null null OutputStrea
  • 涵盖 .NET 中的 TDD、DDD 和设计模式的书籍

    我想要一本能够真正让我全面了解使用 C TDD ASP NET MVC DDD 和设计模式 例如存储库模式 的现代 ASP NET 开发的书 我非常擅长 C 和 ASP NET MVC 但想填补空白 如果您对涵盖这些主题的一两本书有很好的体
  • 如何更改 graphviz 的默认字体大小?

    我使用 doxygen graphviz 来记录我的代码 graphviz 在生成图像方面做得很好 有什么方法可以更改 graphviz 的默认字体大小吗 默认值为 14 但我想使用 12 更改单个元素 例如节点 子图 边缘等 的字体大小确
  • 具有重复参数(可变参数)的磁铁模式

    是否可以使用磁铁图案 http spray io blog 2012 12 13 the magnet pattern 与可变参数 object Values implicit def fromInt x Int Values implic