如何将 `String` 改造成 `Iterable[E]`

How to pimp `String` as `Iterable[E]`

我正在使用 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 声明...

Error:(31, 8) value splitOn is not a member of String possible cause: maybe a semicolon is missing before `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))

那是因为 Iterable[E] 是 Scala 的一个特性,因此是一个相对 "recent" 的发明,而 java.lang.String 是一个基本的 Java 数据类型,自版本以来一直存在1.0。从 1995 年开始。显然,java.lang.String 没有实现 Iterable[E]

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

如果你想拉皮条 String,你必须将 String 作为一个参数传递给你的隐式 class。编译器将拒绝构建多个隐式转换的疯狂塔,否则会使编译时间无法接受。


可以尝试的是这样的:

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] = ???
}

这将为您提供几乎相同的功能,但不需要不受控制的隐式转换爆炸。

String(还有 Array[T])继承自 Java,因此不扩展 Scala 的 Iterable。但是在 Scala 中,有 StringArray[T] 的隐式包装到扩展 IndexedSeq 的对象中,因此 Iterable.

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

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

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

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

此代码将支持正常的 Iterables,以及 Strings 和 Arrays。