0

我正在使用 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 is not a member of 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))
4

2 回答 2

5

这是因为Iterable[E]它是 Scala 特征,因此是一个相对“最近”的发明,而java.lang.String它是自 1.0 版以来一直存在的基本 Java 数据类型。从 1995 年开始。显然,java.lang.String没有实施Iterable[E].

此外,即使存在从Stringto的隐式转换Iterable[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] = ???
}

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

于 2018-03-23T15:26:39.843 回答
0

String (and also Array[T]) are inherited from Java and thus don't extend Scala's Iterable. In Scala though, there are implicit wrappers for String and Array[T] into objects that extend IndexedSeq and accordingly Iterable.

The original interface to request an implicit conversion of an argument was a view bound:

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

It is deprecated now, but you can just request the implicit conversion as an implicit argument:

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

This code will support normal Iterables, and also Strings and Arrays.

于 2018-03-23T18:50:48.267 回答