将 "pimp my Iterable" 扩展到选项
Extend "pimp my Iterable" to Options
最近我在我的代码中发现几个地方我首先收集了一些解决方案,然后仅当解决方案是唯一的(解决方案集合只包含一个元素)时才继续处理它们。以下代码试图以更实用的方式解决此问题。
implicit class GetOnlyOne[A](val coll: Iterable[A]) {
def getonlyone = {
if (coll.isEmpty) None
else if (coll.tail.isEmpty) coll.headOption
else None
}
}
函数可以这样使用:
Seq(1).getonlyone
Seq(1,2).getonlyone
Set(1).getonlyone
目前不起作用的是:
Some(1).getonlyone
是否可以改进函数以接受 Option
,除了 Iterable
s,也许还有视图边界?
您也许可以为 Option
避开一些带有视图边界的东西,但一般的解决方案是定义一个类型类:您定义一个接口并为您想要的每种类型提供该接口的隐式实例支持:
trait CanGetOnlyOne[F[_]] {
def getOnlyOne[A](fa: F[A]): Option[A]
}
object CanGetOnlyOne {
implicit object CanGetOnlyOneIterable extends CanGetOnlyOne[Iterable]{
def getOnlyOne[A](fa: Iterable[A]) = ...
}
implicit object CanGetOnlyOneOption extends CanGetOnlyOne[Option] {
def getOnlyOne[A](fa: Option[A]) = fa
}
}
implicit class GetOnlyOne[F[_], A](fa: F[A])(implicit cgoo: CanGetOnlyOne[F]) {
def getonlyone = cgoo.getOnlyOne(fa)
}
Option
可以隐式转换为 Iterable
,因此以下工作:
implicit class GetOnlyOne[A, Coll](coll: Coll)
(implicit view: Coll => Iterable[A]) {
def getonlyone = {
val it: Iterable[A] = coll
if (it.isEmpty) None
else if (it.tail.isEmpty) it.headOption
else None
}
}
但是对于 Option
来说,这是非常低效的,因为您的 getonlyone
本质上是 identity
函数。因此,我只想为选项引入第二个方法扩展:
implicit class GetOnlyOneOption[A](private val opt: Option[A]) extends AnyVal {
def getonlyone = opt
}
最近我在我的代码中发现几个地方我首先收集了一些解决方案,然后仅当解决方案是唯一的(解决方案集合只包含一个元素)时才继续处理它们。以下代码试图以更实用的方式解决此问题。
implicit class GetOnlyOne[A](val coll: Iterable[A]) {
def getonlyone = {
if (coll.isEmpty) None
else if (coll.tail.isEmpty) coll.headOption
else None
}
}
函数可以这样使用:
Seq(1).getonlyone
Seq(1,2).getonlyone
Set(1).getonlyone
目前不起作用的是:
Some(1).getonlyone
是否可以改进函数以接受 Option
,除了 Iterable
s,也许还有视图边界?
您也许可以为 Option
避开一些带有视图边界的东西,但一般的解决方案是定义一个类型类:您定义一个接口并为您想要的每种类型提供该接口的隐式实例支持:
trait CanGetOnlyOne[F[_]] {
def getOnlyOne[A](fa: F[A]): Option[A]
}
object CanGetOnlyOne {
implicit object CanGetOnlyOneIterable extends CanGetOnlyOne[Iterable]{
def getOnlyOne[A](fa: Iterable[A]) = ...
}
implicit object CanGetOnlyOneOption extends CanGetOnlyOne[Option] {
def getOnlyOne[A](fa: Option[A]) = fa
}
}
implicit class GetOnlyOne[F[_], A](fa: F[A])(implicit cgoo: CanGetOnlyOne[F]) {
def getonlyone = cgoo.getOnlyOne(fa)
}
Option
可以隐式转换为 Iterable
,因此以下工作:
implicit class GetOnlyOne[A, Coll](coll: Coll)
(implicit view: Coll => Iterable[A]) {
def getonlyone = {
val it: Iterable[A] = coll
if (it.isEmpty) None
else if (it.tail.isEmpty) it.headOption
else None
}
}
但是对于 Option
来说,这是非常低效的,因为您的 getonlyone
本质上是 identity
函数。因此,我只想为选项引入第二个方法扩展:
implicit class GetOnlyOneOption[A](private val opt: Option[A]) extends AnyVal {
def getonlyone = opt
}