泛型子类型的隐式 class class
Implicit class for subtypes of a generic class
我想用一些自定义代码增强所有 Iterable
。
为此,我写了以下内容:
implicit class RichIterable[A, B <: Iterable[A]](b: B) {
def nonEmptyOpt: Option[B] = if (b.nonEmpty) Some(b) else None
}
现在,当我想在 List
上使用此方法时,它绝对是 Iterable
的子类,就像这样
List(1, 2, 3).nonEmptyOpt
我明白了
value nonEmptyOpt is not a member of List[Int]
我该如何解决这个问题?
曾经偶然发现的小技巧:
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))
注意参数上的B with Iterable[A]
。
顺便说一句,在调试隐式时,有时尝试显式应用它们(更改之前)会有所帮助:
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
因此,编译器很难确定 A
的类型。类型细化显然有助于它。
给定一个只有 B <: Iterable[A]
类型的参数,编译器不知道如何轻松地找出 A
是什么,因为它不一定很容易从 B
计算出来(需要搜索最小上限)。
相反,您可以通过重新定义类型约束来做到这一点,而无需使用技巧。本质上,B
实际上应该是一个 类型的构造函数 ,它在 Iterable
之上。然后,您的隐式 class 是从一些 B[A]
到您丰富的 class 的转换。具有 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
一个更简单的解决方案是:
implicit class RichIterable[A](b: Iterable[A]) {
def nonEmptyOpt: Option[Iterable[A]] = if (b.nonEmpty) Some(b) else None
}
scala> List(1,2,3).nonEmptyOpt
res0: Option[Iterable[Int]] = Some(List(1, 2, 3))
我想用一些自定义代码增强所有 Iterable
。
为此,我写了以下内容:
implicit class RichIterable[A, B <: Iterable[A]](b: B) {
def nonEmptyOpt: Option[B] = if (b.nonEmpty) Some(b) else None
}
现在,当我想在 List
上使用此方法时,它绝对是 Iterable
的子类,就像这样
List(1, 2, 3).nonEmptyOpt
我明白了
value nonEmptyOpt is not a member of List[Int]
我该如何解决这个问题?
曾经偶然发现的小技巧:
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))
注意参数上的B with Iterable[A]
。
顺便说一句,在调试隐式时,有时尝试显式应用它们(更改之前)会有所帮助:
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
因此,编译器很难确定 A
的类型。类型细化显然有助于它。
给定一个只有 B <: Iterable[A]
类型的参数,编译器不知道如何轻松地找出 A
是什么,因为它不一定很容易从 B
计算出来(需要搜索最小上限)。
相反,您可以通过重新定义类型约束来做到这一点,而无需使用技巧。本质上,B
实际上应该是一个 类型的构造函数 ,它在 Iterable
之上。然后,您的隐式 class 是从一些 B[A]
到您丰富的 class 的转换。具有 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
一个更简单的解决方案是:
implicit class RichIterable[A](b: Iterable[A]) {
def nonEmptyOpt: Option[Iterable[A]] = if (b.nonEmpty) Some(b) else None
}
scala> List(1,2,3).nonEmptyOpt
res0: Option[Iterable[Int]] = Some(List(1, 2, 3))