泛型类的子类型的隐式类

Adr*_*cus 5 scala implicit

我想Iterable用一些自定义代码增强所有s.为此,我写了以下内容:

implicit class RichIterable[A, B <: Iterable[A]](b: B) {
  def nonEmptyOpt: Option[B] = if (b.nonEmpty) Some(b) else None
}
Run Code Online (Sandbox Code Playgroud)

现在,当我想用这种方法在List那绝对是的一个子类Iterable,像这样

List(1, 2, 3).nonEmptyOpt
Run Code Online (Sandbox Code Playgroud)

我明白了

value nonEmptyOpt is not a member of List[Int]
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

Alv*_*sco 7

我偶然发现的小伎俩:

scala> implicit class RichIterable[A, B <: Iterable[A]](b: B with Iterable[A]) {
 |   def nonEmptyOpt: Option[B] = if (b.nonEmpty) Some(b) else None
 | }
defined class RichIterable

scala> List(1,2,3).nonEmptyOpt
res3: Option[List[Int]] = Some(List(1, 2, 3))
Run Code Online (Sandbox Code Playgroud)

请注意B with Iterable[A]参数.

顺便说一句,在调试implicits时,有时会尝试显式应用它们(在更改之前):

scala> new RichIterable(List(1,2,3)).nonEmptyOpt
<console>:15: error: inferred type arguments [Nothing,List[Int]] do not conform to class RichIterable's type parameter bounds [A,B <: Iterable[A]]
          new RichIterable(List(1,2,3)).nonEmptyOpt
Run Code Online (Sandbox Code Playgroud)

因此,编译器很难搞清楚类型A.类型细化显然有助于它.


Mic*_*jac 7

给定一个只有类型的参数B <: Iterable[A],编译器不知道如何轻松地弄清楚是什么A,因为它不一定很容易计算出来B(需要搜索最少的上限).

相反,您可以通过重新定义类型约束来实现此目的,而无需使用技巧.本质上,B应该是一个上面限制的类型构造函数Iterable.然后,您的隐式类是从一些类转换B[A]为您的丰富类.有一个参数B[A]可以帮助编译器计算A,因为它期望它是类型构造函数的参数B.

implicit class RichIterable[A, B[X] <: Iterable[X]](b: B[A]) {
  def nonEmptyOpt: Option[B[A]] = if (b.nonEmpty) Some(b) else None
}

scala> List(1, 2, 3).nonEmptyOpt
res0: Option[List[Int]] = Some(List(1, 2, 3))

scala> List.empty[Int].nonEmptyOpt
res1: Option[List[Int]] = None
Run Code Online (Sandbox Code Playgroud)