【问题标题】:Scala 2.10 implicit function over TraversableOnce should accept an Array but doesn'tTraversableOnce 上的 Scala 2.10 隐式函数应该接受一个数组,但不接受
【发布时间】:2017-05-16 21:39:14
【问题描述】:

我编写了一个简单的隐式函数:mkString() 的一个版本,它的工作方式相同,但如果在任何要连接的参数中找到分隔符,则会引发错误。我想让它适用于所有类似序列的东西,所以我声明如下:

object SafeMkString {
  implicit class SafeMkStringHelper[T](values: TraversableOnce[T]) {
    def safeMkString(sep: String) = {
      values.map { v =>
        val asStr = v.toString
        if (asStr.contains(sep))
          throw new IllegalArgumentException("Value %s in %s contains separator %s" format
            (asStr, values, sep))
        else
          asStr
      }.mkString(sep)
    }
  }
}

这对大多数对象都适用,但在 Scala 2.10 中使用 Array[String] 类型的东西失败了。这是因为 Scala 中的数组只是 Java 数组的别名,并不继承自 TraversableOnce。但是,从ArrayWrappedArray 的隐式转换确实 继承自TraversableOnce。 Scala 中是否有一些规则不允许从 A -> B 然后从 B -> C 进行隐式转换?除了手动创建另一个从Array[T] 显式应用safeMkString 的隐式类之外,还有什么方法可以让这个工作?

【问题讨论】:

    标签: arrays scala implicit-conversion implicit


    【解决方案1】:

    回答您的第一个问题,这是来自Programming in Scala (1st Edition),第 21 章:

    一次一个规则:只尝试一个隐式。编译器永远不会将 x + y 重写为 convert1(convert2(x)) + y。这样做会导致错误代码的编译时间显着增加,并且会增加程序员编写的内容与程序实际执行的内容之间的差异。出于理智的考虑,当编译器已经在尝试另一个隐式转换时,它不会插入进一步的隐式转换。但是,可以通过让implicits 接受隐含参数来规避这个限制,这将在本章后面进行介绍。

    【讨论】:

    • Doh,这确实是 RTFM 的一个案例。
    【解决方案2】:

    受@jwvh 答案的启发(尤其是引文的最后一行),我想出了以下内容:

    implicit class CanBeTraversable[A, T](a: A)(implicit ev: A => TraversableOnce[T]){
      def safeMkString(sep: String) = {
        val values = ev(a)
        ... //put here the body of your method
    }
    

    它的作用是从任何类型 A 进行隐式转换,对于某些 T,该类型隐式转换为 TraversableOnce[T]。这适用于List,因为=:= : List[T] => List[T] 是一种隐式转换(另外,因为Function1 在其第二个参数Function1[List[T], List[T]] <: Function1[List[T], TraversableOnce[T]] 中是协变的)。它也适用于Array,因为它具有到WrappedArray 的隐式转换。

    【讨论】:

      猜你喜欢
      • 2020-03-31
      • 2020-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多