0

我正在编写一个 Scala 程序,其中有一个创建序列的操作。该操作可能会失败,所以我将它包含在一个Try. 我想在 for 理解中进行序列创建和枚举,以便成功创建的序列产生一个元组序列,其中第一个元素是序列,第二个元素是它的一个元素。

为了简化问题,让我的整数序列 aRange并定义一个createRange函数,如果它被要求创建一个奇数长度的范围,它将失败。这是一个简单的理解,可以满足我的要求。

import scala.util.Try

def createRange(n: Int): Try[Range] = {
  Try {
    if (n % 2 == 1) throw new Exception
    else Range(0, n)
  }
}

def rangeElements(n: Int) {
  for {
    r <- createRange(n)
    x <- r
  } println(s"$r\t$x")
}

def main(args: Array[String]) {
  println("Range length 3")
  rangeElements(3)

  println("Range length 4")
  rangeElements(4)
}

如果你运行它,它会正确打印。

Range length 3
Range length 4
Range(0, 1, 2, 3)   0
Range(0, 1, 2, 3)   1
Range(0, 1, 2, 3)   2
Range(0, 1, 2, 3)   3

现在我想重写我的rangeElements函数,以便它返回一个整数序列,而不是作为副作用打印,如果未创建范围,则该序列为空。我想写的是这个。

def rangeElements(n: Int):Seq[(Range,Int)] = {
  for {
    r <- createRange(n)
    x <- r
  } yield (r, x)
}
// rangeElements(3) returns an empty sequence
// rangeElements(4) returns the sequence (Range(0,1,2,3), 0), (Range(0,1,2,3), 1) etc.

这给了我两个类型不匹配的编译器错误。r <- createRange(n)需要Seq[Int]但找到的行scala.util.Try[Nothing]x <- r需要scala.util.Try[?]但找到的行scala.collection.immutable.IndexedSeq[Int]

大概有某种类型的擦除Try让我感到困惑,但我无法弄清楚它是什么。我在 for comprehension 中尝试了各种限定词toOptiontoSeq但无济于事。

如果我只需要产生范围元素,我可以按照下面前两个答案的建议明确处理我自己的SuccessFailure条件。createRange但是,我需要访问范围及其各个元素。

我意识到这是一个听起来很奇怪的例子。我要解决的真正问题是复杂的递归搜索,但我不想添加它的所有细节,因为这只会混淆这里的问题。

如何编写rangeElements以产生所需的序列?

4

2 回答 2

3

如果您将 for 理解转换为它的 map/flatMap 实现(如Scala 语言规范 6.19中所述),问题就会变得清晰。flatMap 具有结果类型Try[U],但您的函数需要Seq[Int].

for {
  r <- createRange(n)
  x <- r
} yield x

createRange(n).flatMap {
  case r => r.map {
    case x => x
  }
}

你有什么理由不使用这种getOrElse方法吗?

def rangeElements(n: Int):Seq[Int] =
  createRange(n) getOrElse Seq.empty
于 2013-07-24T22:24:11.463 回答
1

Trywill be Successwith a Rangewhen是n偶数或 a Failurewith an Exceptionwhenn是奇数。在rangeElements匹配并提取这些值。Success将包含有效的Range并将Failure包含Exception. 而不是Exception返回一个空的Seq

import scala.util.{Try, Success, Failure}

def createRange(n: Int): Try[Range] = {
  Try {
    if (n % 2 == 1) throw new Exception
    else Range(0, n)
  }
}

def rangeElements(n: Int):Seq[Tuple2[Range, Int]] = createRange(n) match {
  case Success(s) => s.map(xs => (s, xs))
  case Failure(f) => Seq()
}    

scala> rangeElements(3)
res35: Seq[(Range, Int)] = List()

scala> rangeElements(4)
res36: Seq[(Range, Int)] = Vector((Range(0, 1, 2, 3),0), (Range(0, 1, 2, 3),1), (Range(0, 1, 2, 3),2), (Range(0, 1, 2,3),3))
于 2013-07-24T22:18:11.327 回答