2015-07-21 45 views
0

最近,我在代碼中發現了幾個我第一次收集某些解決方案的地方,然後僅在解決方案是唯一的時才繼續處理它們(解決方案集合僅包含一個元素)。以下代碼是嘗試以更多功能的方式解決此問題。將「pimp my Iterable」擴展爲選項

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小號,也許有看法界限?

回答

3

您也許能夠bodge與視圖邊界東西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) 
} 
2

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 
}