【问题标题】:Tree recursion - How to avoid 'missing return at end of function'? [closed]树递归 - 如何避免“函数结束时缺少返回”? [关闭]
【发布时间】:2020-09-24 08:21:59
【问题描述】:

对于insects combinatorics的实验室问题,下面是我使用树递归的解决方案:

func Paths(m int, n int) int {
    length := m
    width := n

    var f func(int, int) int

    f = func(h int, v int) int {
        if h == width && v == length {
            return 1
        } else if h < width && v < length {
            return f(h, v+1) + f(h+1, v)
        } else if v < length {
            return f(h, v+1)
        } else if h < width {
            return f(h+1, v)
        } /*else { // this condition doesn't occur
            return 0
        }*/
    } // Line 19

    return f(1, 1)
}

上述解决方案不需要else块(无效),但编译器在第19行给出missing return error

上述代码如何避免missing return error

【问题讨论】:

  • "如何避免丢失返回错误" --- 每个函数路径都应该以return 结尾。所以,为了避免它 - 你应该 return 一个整数。
  • 一方面,条件不能发生并不明显(事实上,创建它确实发生的情况是微不足道的,例如Paths(0, 0)):去抱怨是对的。如果有一定的把握,重写代码使其更明显。另一方面,您确定条件中没有错误吗?您有时会将hlength 进行比较,有时将其与width 进行比较(反之亦然v)。在不知道您要解决的问题的情况下,这似乎是先验不可能的。
  • 与您的问题无关,但没有理由这样做return } else。只需删除其他。
  • @KonradRudolph 嘿,你是对的 h 应该始终与 width 进行比较。查询已编辑.. 错字

标签: go recursion


【解决方案1】:

Go 不知道// this condition doesn't occur,当分析你的代码时,它发现如果if 语句的条件都不满足,它就缺少返回值。

“解决”此问题的一种方法是执行panic("does not occur") 之类的操作。不过,我不喜欢这样,因为这些年来我遇到了太多的日志条目说“不会发生”......

或者,您可以使用 Go 中可能更自然的方法:

if cond1 {
  return v1
}
if cond2 {
  return v2
}
//... other cases ... 
return v3

或者甚至是一个 switch 语句:

switch {
case cond1:
  return v1
case cond2:
  return v2
//... other cases ... 
default:
  return v3
} 

您使用的“else if”是不必要的,因为每种情况都会导致函数立即返回。检查 Effective Go 以了解此模式。它也在标准库中被广泛使用(即避免不必要的 else's)。

另外,既然你说绝对不可能所有条件都为假,所以没有必要测试最后一个:这是“其他”情况。

【讨论】:

【解决方案2】:

您明确指出函数 f 返回一个 int,问题是此函数中存在条件不满足您的任何 if...elseif 条件的情况:

package main

import "fmt"

func main() {
    fmt.Println(Paths(0, 0))
    fmt.Println(Paths(1, 0))
    fmt.Println(Paths(0, 1))
}

func Paths(m int, n int) int {
    length := m
    width := n

    var f func(int, int) int

    f = func(h int, v int) int {
        if h == length && v == width {
            return 1
        } else if h < width && v < width {
            return f(h, v+1) + f(h+1, v)
        } else if v < length {
            return f(h, v+1)
        } else if h < width {
            return f(h+1, v)
        } else { // this condition does occur
            return 0
        }
    } // Line 19

    return f(1, 1)
}

所以这些场景是函数允许的。您可能会在输入此函数之前验证这些值,但问题是此函数不执行任何操作,并且传递这些值是有效的。

如果你确信 0,0; 0,1;并且 1,0 不会是输入值,您可以通过 else 避免最后一个 else if h &lt; width {;但是这会改变函数的逻辑。同样,鉴于函数 Paths 已导出,您可能应该对传入的值进行验证,如果您需要确保 0,0; 0,1;和 1;0 选项是不允许的。

如果它符合您的目的,您可以在函数末尾有一个返回,用于返回 0 或 -1 以指示该值不正确。就个人而言,如果这些值在函数中是不可接受的,最好验证输入并返回错误,或者如果必须,请恐慌。

func Paths(m int, n int) int {
    length := m
    width := n

    var f func(int, int) int

    f = func(h int, v int) int {
        if h == length && v == width {
            return 1
        } else if h < width && v < width {
            return f(h, v+1) + f(h+1, v)
        } else if v < length {
            return f(h, v+1)
        } else if h < width {
            return f(h+1, v)
        }

        return 0
    }

    return f(1, 1)
}

【讨论】:

  • 对答案真的投反对票的人应该留下解释性评论,尤其是当答案像这样深思熟虑时。
  • @KonradRudolph 嘿...我没有投反对票,但那是错字。@ 987654324@ 应始终与width 进行比较...这是错字。我认为我们不需要答案来纠正hwidth 的比较。我认为最后的return 0 实际上在概念上具有误导性,除了满足 GO 语法。我们应该删除它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-17
  • 2015-09-19
  • 1970-01-01
  • 2020-10-14
  • 2013-03-10
  • 2012-12-11
相关资源
最近更新 更多