如何在编写Spray指令(Shapeless,Scala)时获得HList的第一个Some



假设我想创建一个简单的指令来从HTTP请求中获取会话标识符,但有一个转折点:该请求可能使用旧格式,但由于向后兼容性,两者中的任何一个都应被视为当前有效。

我勾勒出了一个简单的东西,它基本上构成了两个现有的指令,最终的指令是一个…

Directive[Option[String] :: Option[String] :: HNil]

这是我问题的核心:有没有什么简洁的方法可以基本上说"给定一个指令,它是多个选项的HList,得到第一个Some,然后使用它,否则使用默认值"?

我目前的执行情况。工作,但看起来有点乱,根本无法重复使用。

def sessionIdentifier: Directive1[String] = {
  (optionalHeaderValueByName("New-Session-Header") & parameter("oldsessionparam"?)).hmap {
    case Some(x) :: _ :: HNil if x.nonEmpty => x
    case _ :: Some(x) :: HNil if x.nonEmpty => x
    case _ => getNewSessionId()
  }
}

如果所有元素类型都保证为Option[String]类型,那么下面的内容将稍微简洁一点,

@ import shapeless._
import shapeless._
@ val opts = Option.empty[String] :: Option("foo") :: Option("bar") :: HNil
opts: Option[String] :: Option[String] :: Option[String] :: HNil = ...
@ opts.toList.flatten.headOption.getOrElse("default")
res0: String = "foo"

实际上,您的实现非常好。它可能被重构为

val sessionParameters =
  optionalHeaderValueByName("New-Session-Header") & parameter("oldsessionparam".?)
val sessionIdentifier =
  sessionParameters.hmap {
    case newId :: oldId :: HNil =>
      newId.filter(_.nonEmpty)
        .orElse(oldId.filter(_.nonEmpty))
        .getOrElse(getNewSessionId())
  }

最新更新