从Some(Some(Some(Some(10))))
获得10分的最简洁方法是什么?
不使用像Scalaz这样的外部库。
答案 0 :(得分:10)
import scala.language.higherKinds
case class Flattener[W[_], WW, T](fn : WW => W[T])
implicit def optionRecFlattenFn[WW, T](
implicit f : Flattener[Option, WW, T] = Flattener((ww: WW) => Option(ww))
) = Flattener((ww : Option[WW]) => ww.flatMap(f.fn))
def optionRecursiveFlatten[WW, T](www : Option[WW])(
implicit f : Flattener[Option, Option[WW], T]
) = f.fn(www)
val nestedOption = Option(Option(Option(Option(10))))
// Some(Some(Some(Some(10))))
val flatOption = optionRecursiveFlatten(nestedOption)
// Some(10)
val evenMoreNestedOption = Option(Option(Option(Option(Option(Option(10))))))
// Some(Some(Some(Some(Some(Some(10))))))
val flatOption2 = optionRecursiveFlatten(evenMoreNestedOption)
// Some(10)
答案 1 :(得分:4)
如果您事先不知道嵌套级别,这将适用于任何级别:
def unwrapRec(o: Option[Any]) : Any = o match {
case Some(inner @ Some(_)) => unwrapRec(inner)
case Some(x) => x
case _ => ???
}
但是,请注意返回Any
。您可以将其更改为您喜欢的任何类型并相应地调整模式匹配,但我认为您必须传入Option[Any]
。所以此时它并不是类型安全的。
答案 2 :(得分:0)
您可以在嵌套flatten
上重复使用Option[Option[A]]
:
scala> val a = Some(Some(Some(Some(10))))
a: Some[Some[Some[Some[Int]]]] = Some(Some(Some(Some(10))))
scala> a.flatten.flatten.flatten.get
res0: Int = 10
我认为从A
中提取T[A] := Option[T[A]] | A
并不存在任何通用且类型安全的方式。
编辑:此方法可以动态获取内容,返回最里面的值,或None
:
def unwrap(x: Any): Any = x match {
case Some(v) => unwrap(v)
case v => v
}
scala> unwrap(Some(Some(Some(Some(10)))))
res1: Any = 10
scala> unwrap(Some(None))
res2: Any = None
遗憾的是,类型过于宽泛:Any => Any
。