【问题标题】:Can Scala's implicits compose to convert higher-kinded types?Scala 的隐式可以组合来转换更高种类的类型吗?
【发布时间】:2011-07-26 00:48:55
【问题描述】:

假设我有一个名为 LongArrayWritable 的类型,它是 Long 数组的装箱表示。我有在这些类型之间转换的隐式定义:

implicit def boxLongArray(array: Array[Long]) : LongArrayWritable { /*elided*/}
implicit def unboxLongArray(array: LongArrayWritable) : Array[Long] { /*elided*/}

现在,我也有隐式在 java.lang.Iterable 和 scala.collection.List[X] 之间转换的通用形式:

implicit def iterator2list[X](it : java.lang.Iterable[X]) : List[X] { /* elided */ }
implicit def list2iterator[X](list : List[X]) : java.lang.Iterable[X] { /* elided */ }

通过这些定义,scala 编译器能否推断出 java.lang.Iterable[LongArrayWritable] 和 List[Array[Long]] 之间的隐式转换(相当于iterator2list(iterator).map(unboxLongArray(_))),或者这超出了implicits 的能力,因此需要它自己的(显式?)隐式定义?

谢谢,

提姆

【问题讨论】:

  • 只是文体评论;我倾向于回避这种隐式转换,因为我认为它们会妨碍可读性并掩盖潜在的昂贵操作。可以在此处找到我认为更可取的样式的示例:scala-lang.org/api/current/scala/collection/…(与同一包中的 JavaConversions 相比)
  • 另外,我不确定更高类型的类型与这个问题有什么关系;您没有在此代码中的任何地方抽象类型构造函数。
  • 啊 - 两个优点。我可以理解隐式如何掩盖转换操作的成本 - 我一直试图从我的代码中删除所有显式转换,这可能不是一个特别好的设计决策。关于更高种类的类型,我想我在这里可能稍微混淆了我的术语 - 我很可能将更高种类的类型与参数化类型混淆了。实际上,我对区别并不完全清楚,但这可能完全是一个单独的问题! :-)
  • 简而言之,更高种类的类型允许您对参数化类型进行抽象。例如,List[Int] 是一个类型; List 是一个参数的类型构造函数;它本身不是一种类型。据说List[Int] 有一种类型*,而List 有一种类型* -> *,这意味着它需要另一种类型才能给出一个类型。现在,想象一个特征Foo[M[_]] - 在这里,您可以使用一个参数的任何类型构造函数(种类* -> *)参数化Foo,因此例如您可以创建Foo[List]Foo[Option],但不能创建Foo[List[Int]]因为List[Int] 有错误的种类。希望有帮助!

标签: generics scala types implicits


【解决方案1】:

有一篇文章涵盖了这个问题:How can I chain implicits in Scala?。本质上,您需要有一个视图绑定到LongArrayWritable 的转换。这意味着,转换为LongArrayWritable 的隐式def 接收一个隐式参数(称为视图绑定),因此此def 的参数不是直接Array,而是可以转换为@987654327 的某种类型@:

object LongArrayWritable {
  implicit def fromArraySource[A <% Array[Long]](a: A): LongArrayWritable = apply(a)
}
case class LongArrayWritable(a: Array[Long])

def test(a: LongArrayWritable): Unit = println("OK")

现在这适用于数组:

test(Array( 1L, 2L, 3L))

但是,由于Array 不是Iterable,并且在范围内没有从IterableArray 的默认转换,您需要添加一个:

implicit def iterable2Array[A: ClassManifest](i: Iterable[A]): Array[A] = i.toArray

然后就可以了:

test(List(1L, 2L, 3L))

视图绑定A &lt;% Array[Long]A =&gt; Array[Long] 类型的隐式参数的快捷方式,因此您也可以编写

implicit def fromArraySource[A](a: A)(implicit view: A => Array[Long]) ...

【讨论】:

  • 谢谢,很抱歉延迟回复。现在一切都非常清楚了!
猜你喜欢
  • 2011-06-08
  • 2016-10-23
  • 2011-09-09
  • 1970-01-01
  • 1970-01-01
  • 2011-04-18
  • 1970-01-01
  • 2023-03-21
  • 1970-01-01
相关资源
最近更新 更多