当get获得成功时,Option.get的更好替代品

时间:2015-01-25 13:32:06

标签: scala

添加Scalaz Maybe的原因之一是get rid of get

  

与std lib选项的一些区别:

     
      
  • 没有不安全的获取方法
  •   

我理解get可能不安全,但有时是安全的(在Option不为空之前已经验证的代码中)。在某些情况下,人们可以轻易地远离使用get,但有时对我来说并不那么明显。以下代码中get的替代方法是什么?

def point(cursor:Int) : Option[XY]

def paste(cs: Seq[Int]) = {
  if (validateSelection(cs)) {
    cs.size match {
      case 2 => // between two points
        // editablePoint returning Option for general case,
        // but here it is known to succeed as validateSelection passed
        val beDiff = point(cs.head).get.xy - point(cs.last).get.xy
        ...
    case _ =>
      ...
  }
  ...
}

1 个答案:

答案 0 :(得分:1)

要摆脱准安全get,您必须重构validateSection。在您的示例中,它可能会返回Boolean

def validateSection(cs: Seq[Int]): Boolean

然而,您可以返回证据cs有效:

/* Returns the first and last values of the sequence,
 * if the sequence's length == 2. Otherwise `Empty`.
 */
def validateSection(cs: Seq[Int]): Maybe[(Int, Int)]

然后你可以将你的代码片段重构为:

def paste(cs: Seq[Int]) = {
  match validateSelection(cs) {
    case (first, last) => 
      val beDiff = first - last
        ...
    case _ =>
      ...
  }
  ...
}

编辑您可以进一步理解:创建辅助类型以消除功能的偏好。

point返回Option[XY],即它是部分的。我们应该尝试使输入参数更精确,因此point可以是总计,即返回XY。在不知道精确规格的情况下,我只能勾勒出解决方案:

case class Selection(/* ... */)

/* Constructed from `Selection` */
case class Cursor()

object Selection {
  def first: Cursor = ???
  def last: Cursor = ???
}

/* If `cs` is valid, we return a `ValidSelection`, othersise `Empty`. */
def validateSelection(cs: Seq[Int]): Maybe[Selection]

/* With more precise type, we can have total `point`. */
def point(cursor: Cursor): XY

这种方法最初可能看起来像样子,但在这里我们使用了类型系统的优势。避免使用stringly typed列表类型的编程。