从嵌套选项中提取值

时间:2016-09-20 18:16:55

标签: scala

Some(Some(Some(Some(10))))获得10分的最简洁方法是什么?

不使用像Scalaz这样的外部库。

3 个答案:

答案 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