如何将`String`作为`Iterable [E]`

时间:2018-03-23 15:11:43

标签: scala scala-generics

我正在使用Scala的implicit class机制,无法将java.lang.String识别为Iterable[A]

implicit class PStream[E](stream: Iterable[E]) {
    def splitOn(test: Iterable[E] => Boolean): Option[(Iterable[E], Iterable[E])] = {
        ???
    }
}

只有上面的定义,IntelliJ和SBT声明......

  

错误:(31,8)value splitOn不是String的成员   可能的原因:在'value splitOn'之前可能缺少分号?                           .splitOn(s => Character.isWhitespace(s.head))

......当我试着这个......

            line: String =>
                val Some((identifier: String, patternn: String)) =
                    line
                        // take the identifier
                        .splitOn(s => Character.isWhitespace(s.head))

2 个答案:

答案 0 :(得分:5)

那是因为Iterable[E]是一个Scala特征,并且是一个相对“最近”的发明,而java.lang.String是从1.0版开始就存在的基本Java数据类型。从1995年开始。显然,java.lang.String没有实现Iterable[E]

此外,即使存在从StringIterable[E]的隐式转换,Scala也永远不会尝试对单个表达式进行多次隐式转换。

如果您想要pimp String,则必须将String作为单个参数传递给隐式类。编译器将拒绝构建多个隐式转换的疯狂塔,因为这会使编译时间无法接受。

可以尝试尝试的是:

implicit def toPStreamOps[X, E](x: X)(implicit iter: IsIterable[X, E])
: PStream[X, E] = ???

然后提供单独的

implicit object StringIsIterableChar 
extends IsIterable[String, Char] {
  def asIterable(s: String): Iterable[Char] = ???
}

这会给你几乎相同的功能,但它不需要不受控制的隐式转换爆炸。

答案 1 :(得分:0)

String(以及Array[T])继承自Java,因此不会扩展Scala的Iterable。但是在Scala中,StringArray[T]包含了对IndexedSeqIterable扩展的对象的隐式包装。

请求隐式转换参数的原始接口是view bound

implicit class PStream[E, T <% Iterable[E]](stream: T) { 
  /* ... */
}

现在已弃用,但您可以将隐式转换请求为隐式参数:

implicit class PStream[E, T](stream: T)(implicit toIterable: T => Iterable[E]) { 
  /* ... */
}

此代码将支持普通Iterable以及StringArray s。