首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Scala似乎需要递归函数的“返回”关键字。

Scala似乎需要递归函数的“返回”关键字。
EN

Stack Overflow用户
提问于 2022-07-05 11:16:46
回答 3查看 81关注 0票数 1

我是Scala的新手,我知道“返回”关键字是多余的。但是,在编写递归函数时,如果“返回”关键字丢失,则当满足所需条件时,控件不会从调用堆栈返回。

下面是一个代码,以检查是否有平衡括号-

使用“返回”(工作正常):

代码语言:javascript
复制
  def balance(chars: List[Char]): Boolean = {
    def parenBalance(char : List[Char])  :Boolean = {
      parenBalanceRecur(char, 0 , 0)
    }

    def parenBalanceRecur(charSequence: List[Char], itr : Int, imbalance : Int) : Boolean = {
      if (imbalance < 0) then return false
      if (itr == charSequence.length ) {
        if (imbalance == 0) then return true else return false
      }

      if (charSequence(itr) == '(')  {
        parenBalanceRecur(charSequence, (itr + 1), (imbalance + 1))
      }
      else if (charSequence(itr) == ')') {
        parenBalanceRecur(charSequence, itr + 1, imbalance -1)
      }
      else {
        parenBalanceRecur (charSequence, itr +1, imbalance)
      }
    }
    parenBalance(chars)
  }

如果没有返回(成功计算#1,但不返回,则在#2处使用IndexOutOfBoundsException失败):

代码语言:javascript
复制
  def balance(chars: List[Char]): Boolean = {
    def parenBalance(char : List[Char])  :Boolean = {
      parenBalanceRecur(char, 0 , 0)
    }

    def parenBalanceRecur(charSequence: List[Char], itr : Int, imbalance : Int) : Boolean = {
      if (imbalance < 0) then  false
      if (itr == charSequence.length ) {
        if (imbalance == 0) then true else false // #1
      }

      if (charSequence(itr) == '(')  {  // # 2
        parenBalanceRecur(charSequence, (itr + 1), (imbalance + 1))
      }
      else if (charSequence(itr) == ')') {
        parenBalanceRecur(charSequence, itr + 1, imbalance -1)
      }
      else {
        parenBalanceRecur (charSequence, itr +1, imbalance)
      }
    }
    parenBalance(chars)
  }

这是针对尾递归的吗?请帮我理解一下。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-07-05 15:45:41

正如目前实现的那样,parenBalanceRecur()有3个顶级if表达式,每个表达式都计算为一个布尔值,但是scala中的规则是,函数的最后一个表达式是函数=>的返回值--前两个表达式被忽略。

第二个实现中的=>:

代码语言:javascript
复制
def parenBalanceRecur(charSequence: List[Char], itr : Int, imbalance : Int) : Boolean = {
      if (imbalance < 0) then  false
      if (itr == charSequence.length ) {
        if (imbalance == 0) then true else false // #1
      }

      if (charSequence(itr) == '(')  {  // # 2
        parenBalanceRecur(charSequence, (itr + 1), (imbalance + 1))
      }
      else if (charSequence(itr) == ')') {
        parenBalanceRecur(charSequence, itr + 1, imbalance -1)
      }
      else {
        parenBalanceRecur (charSequence, itr +1, imbalance)
      }
    }
    parenBalance(chars)
  }

第一个表达式if (imbalance < 0) then false将计算为true或false,但该表达式与代码=>的其余部分断开连接--函数没有使用该布尔值执行任何操作。我们也可以写val thisAchievesNothing = if (imbalance < 0) then false。我们的thisAchievesNothing将保存一些值,这是有效的语法,但不是很有用。

同样,这也是:

代码语言:javascript
复制
if (itr == charSequence.length ) {
        if (imbalance == 0) then true else false // #1
      }

将计算为另一个同样被忽略的布尔值。

最后,最后一个if... else if... else也将计算为另一个布尔值,因为这个布尔值是函数的最后一个表达式,所以它只会是返回的值。

尝试将parenBalanceRecur重写为一个单一的if.. else if... else if ...表达式,而不是3,然后行为将与使用return的实现相同。

(我们倾向于避免使用return,因为它是一种做某事的语句,而习惯是编写一些有价值的函数/表达式)

票数 2
EN

Stack Overflow用户

发布于 2022-07-05 15:44:00

正如在一些注释中提到的,您不能只在没有return关键字的情况下短路路径并返回一个值。仅在方法的最后一个值时才需要return。在任何情况下,通常,这是一个很好的做法,以避免短路的多重回报在一个方法。在您的示例中,添加两个else,您可以构造到每个可能输出的最后一个值的路径,而无需使用return关键字:

代码语言:javascript
复制
def balance(chars: List[Char]): Boolean = {
  def parenBalance(char : List[Char])  :Boolean = {
    parenBalanceRecur(char, 0 , 0)
  }

  @tailrec
  def parenBalanceRecur(charSequence: List[Char], itr : Int, imbalance : Int) : Boolean = {
    if (imbalance < 0) then false
    else if (itr == charSequence.length ) {
      if (imbalance == 0) then true else false // #1
    }

    else if (charSequence(itr) == '(')  {  // # 2
      parenBalanceRecur(charSequence, (itr + 1), (imbalance + 1))
    }
    else if (charSequence(itr) == ')') {
      parenBalanceRecur(charSequence, itr + 1, imbalance -1)
    }
    else {
      parenBalanceRecur (charSequence, itr +1, imbalance)
    }
  }
  parenBalance(chars)
}
票数 3
EN

Stack Overflow用户

发布于 2022-07-05 18:18:05

除了公认的答案外,还有一些值得考虑的问题:

  • 使用@
  • ,因此您的递归方法将得到编译器优化的尾调用。否则,它可能会对非常大的列表产生堆栈溢出。(虽然这里可能不是这样的,但是在Scala中实现尾递归methods).
  • List是一个单链接列表时,请始终考虑使用这个注释,因此它没有被索引。对每个递归调用使用cs(iter)使您的方法能够在线性时间内获得每个索引的元素。这意味着你会得到O(n^2)的复杂性。作为另一种选择,要么使用基于索引并为O(1)中的每个元素提供的chars: Array[Char],要么继续使用list,但转而切换到模式匹配。
  • 的次要内容:从if表达式中删除只包含一个语句的冗余大括号;可以删除parenBalance并直接调用parenBalanceRecur(char, 0 , 0)作为balance中的最后一条语句;为balance使用默认值。

我在代码中的建议:

代码语言:javascript
复制
  def isBalanced(chars: List[Char]): Boolean = {
    @tailrec
    def balance(cs: List[Char], imbalances: Int = 0): Boolean =
      if (imbalances < 0) false
      else cs match {
          case Nil => imbalances == 0
          case x :: xs =>
            if (x == '(') balance(xs, imbalances + 1)
            else if (x == ')') balance(xs, imbalances - 1)
            else balance(xs, imbalances)
        }

    balance(chars)
  }

  println(isBalanced("()".toList))          // true  
  println(isBalanced("()(())".toList))      // true
  println(isBalanced(")(".toList))          // false
  println(isBalanced("(()))".toList))       // false
  println(isBalanced("((((()))))".toList))  // true
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72868510

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档