Scala 当get保证成功时,它是Option.get的更好选择

Scala 当get保证成功时,它是Option.get的更好选择,scala,Scala,添加Scalaz的原因之一是: 与std lib选项的一些区别: 没有不安全的get方法 我理解get可能不安全,但有时是安全的(在选项不为空之前已验证的代码中)。在某些情况下,人们可以很容易地避免使用get,但有时这对我来说并不明显。在下面的代码中,除了get,还有哪些替代方案 def point(cursor:Int) : Option[XY] def paste(cs: Seq[Int]) = { if (validateSelection(cs)) { cs.size

添加Scalaz的原因之一是:

与std lib选项的一些区别:

  • 没有不安全的get方法
我理解
get
可能不安全,但有时是安全的(在
选项
不为空之前已验证的代码中)。在某些情况下,人们可以很容易地避免使用
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 _ =>
      ...
  }
  ...
}

要摆脱准安全的
get
,必须重构
validateSection
。在您的示例中,它可能返回一个
布尔值

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 _ =>
      ...
  }
  ...
}

编辑你可以更进一步:创建辅助类型来摆脱函数的偏爱

返回
选项[XY]
,即它是部分的。我们应该尽量使输入参数更精确,因此
可以是总的,即返回
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

这种方法一开始可能看起来像是陈词滥调,但在这里我们利用了拥有类型系统的优势。避免或列出类型的编程。

validateSection
验证任何长度的选择,并告诉我任何
调用都将成功。不过,我理解你所写内容的精神。它根本不进行验证,将验证留给
调用本身,然后正确处理故障。调用可以被提取到一个初始位置,并提交一个条件,以避免出现“意大利面条”的条件。@Suma,我用进一步的重构方法修改了答案。