2017-05-16 26 views
0

我写了一个简单的隐式函数:mkString()的一个版本工作原理相同,但如果在连接的任何参数中都找到分隔符,则会引发错误。我想,使其工作在所有序列状的东西,所以我声明,如下所示:Scala 2.10在TraversableOnce上的隐式函数应该接受一个数组,但不会

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

这工作对大多数的对象,但在斯卡拉2.10 Array[String]类型的东西失败。这是因为Scala中的数组只是Java数组的别名,并不会从TraversableOnce继承。但是,存在从ArrayWrappedArray的隐式转换,即确实从TraversableOnce继承。 Scala中有一些规则不允许从A→B然后从B→C进行隐式转换?除了手动创建另一个隐式类,明确应用safeMkStringArray[T]以外,有什么方法可以实现此工作吗?

回答

3

在回答你的第一个问题,这是从Programming in Scala (1st Edition),第21章:

一在一次一个规则:只有一个隐含的尝试。编译器将永远不会将x + y重写为convert1(convert2(x))+ y。这样做会导致编译时间在错误代码上显着增加,并且会增加程序员编写的内容与程序实际执行的内容之间的差异。为了理智,当编译器已经在尝试另一个隐式转换时,编译器不会插入更多的隐式转换。然而,通过隐含隐含参数可以规避这种限制,本章后面将对此进行介绍。

+0

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

相关问题