我有一些用户提供的值Option[String]
。我想仅在它们非空时验证它们。
验证只是检查字符串是否可以转换为int,并且不小于0.
有没有办法简化这段代码,或者让它更具可读性?
val top: Option[String] = ...
val skip: Option[String] = ...
val validationErrors = new ListBuffer[Err]()
top match {
case Some(x) => if (x.toIntOpt.isEmpty || x.toIntOpt.get < 0) validationErrors += PositiveIntegerRequired("$top")
}
skip match {
case Some(x) => if (x.toIntOpt.isEmpty || x.toIntOpt.get < 0) validationErrors += PositiveIntegerRequired("$skip")
}
这是toIntOpt助手:
def toIntOpt: Option[Int] = Try(s.toInt).toOption
答案 0 :(得分:3)
是的,通过使用flatMap
和for-comprehensions
以及collect
可以简化它:
def checkInt[A](stringOpt: Option[String], a: A): Option[A] = for {
s <- stringOpt
i <- s.toIntOpt if (i < 0)
} yield a
val validationErrors = List(
checkInt(top, PositiveIntegerRequired("$top")),
checkInt(skip, PositiveIntegerRequired("$skip"))
).collect {
case Some(x) => x
}
如果原始checkInt
非空且包含无效的负整数,则第一个函数a
会返回值Option
。
然后我们将两者放入List并仅收集非空的值,从而产生List
Err
,而无需创建中间Buffer
。
使用cat库中的Validated
类型可以找到更简单的方法:https://typelevel.org/cats/datatypes/validated.html
答案 1 :(得分:0)
使用for-comprehension
的替代方法是将map
与filter
一起使用。
top.map(toIntOpt)
.filter(i => i.getOrElse(-1) < 0)
.foreach(_ => validationErrors += PositiveIntegerRequired("$top"))
map
调用将生成Option[Option[Int]]
,然后根据嵌套Option
的值对其进行过滤(如果选项为{{1,则默认为-1
}})。