Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Recursion 对于Go中的递归函数,如果内部函数返回,外部函数是否正常继续执行?_Recursion_Go_Dereference_Panic - Fatal编程技术网

Recursion 对于Go中的递归函数,如果内部函数返回,外部函数是否正常继续执行?

Recursion 对于Go中的递归函数,如果内部函数返回,外部函数是否正常继续执行?,recursion,go,dereference,panic,Recursion,Go,Dereference,Panic,好的,我有这段代码 func registerDomain(domainName string, n int) bool { //building the request here resp, errr := client.Do(r) if errr != nil { if n == 1 { return false } registerDomain(domainName, n-1) }

好的,我有这段代码

func registerDomain(domainName string, n int) bool {
    //building the request here 
    resp, errr := client.Do(r)
    if errr != nil { 
        if n == 1 {
            return false
        }
        registerDomain(domainName, n-1)
    }

    bodyBytes, err2 := ioutil.ReadAll(resp.Body)
    if err2 == nil {
        resp.Body.Close()
        //handle bodyBytes
        //if the response is how it should be return true, if it's not call the function again with n-1
    } else { //if there is an error reading the response
        resp.Body.Close()
        if n == 1 {
            return false
        }
        registerDomain(domainName, n-1)
    }
    return false //it should never reach this line
}
说明:

我用一个参数n(比如5)调用函数,该参数表示函数在出现错误时重试的次数。每次出现问题时,我都使用n-1进行递归调用,因此当它达到n=1时,它就会放弃并返回false。这段代码在实践中工作得很好,它完成了它应该做的事情,有时当响应不正确时,它会递归地调用自己,并在第二次(或第三次、第四次…)工作。当问题在n=1之前未修复时,返回false

问题是:

这是一个大代码的一部分,该代码应该运行17个小时左右,当它试图从身体中读取时,它会感到恐慌,有时在这行:

bodyBytes, err2 := ioutil.ReadAll(resp.Body)
它表示panic:runtime错误:无效内存地址或零指针解引用。现在我知道这可能意味着它试图从一个不存在的resp.Body读取,但它清楚地指出,当err为nil时,resp总是包含一个非nil resp.Body

所以,在我看来,这可能是一些递归调用。对我来说唯一有意义的是这个场景:假设errr不是nil(这意味着resp.Body不存在),所以它进入if errr!=零,因为n=1,它将再次调用自身,n=4。让我们假设这一次一切正常,第二个函数返回第一个函数的true,但第一个函数继续执行,并尝试从不存在的resp.Body读取。这引起了恐慌,我们现在

所以,我需要的是有人确切地知道递归函数是如何工作的,如果不是这样,我可以在阅读表单之前检查resp.Body的存在,或者做一些有帮助的事情

无论如何,谢谢!:)


更新:你很好,我的代码不再恐慌,我也不会。非常感谢!(我不确定这是否是更新的地方)

您需要在第一次registerDomain调用后返回,否则当您对registerDomain的调用完成时,您将在ioutil.ReadAll上死机

//building the request here 
resp, errr := client.Do(r)
if errr != nil { 
    if n == 1 {
        return false
    }
    return registerDomain(domainName, n-1)
}
改变

registerDomain(domainName, n-1)


这样,外部函数将不会继续执行,也不会从nil body读取。

registerDomain()函数中,有两个地方可以调用自身

如果
client.Do()
失败(
errr!=nil
),您将再次调用
registerDomain()
。有时它会返回,当它返回时,您的代码将继续执行,尝试从
resp.Body
读取,但这很可能是
nil
,因为
errr!=无

以下是您应该如何处理它:

无论何时进行递归调用,当调用返回时,不应让代码继续,而应返回它返回的值,如下所示:

return registerDomain(domainName, n-1)
可供替代的 您试图解决的问题可以使用
for
语句在不递归的情况下解决。
变体将更加清晰和简单

修改
registerDomain()
函数,使其在每次调用自身时返回false,并使用此循环重试5次:

var result bool
for i := 0; i < 5; i++ {
    result = registerDomain(domainName) // You don't need to pass n anymore
    if result {
        break
    }
}

if result {
    fmt.Println("Domain registered successfully!")
} else {
    fmt.Println("Failed to register domain!")
}
var结果bool
对于i:=0;i<5;i++{
result=registerDomain(域名)//不再需要传递n
如果结果{
打破
}
}
如果结果{
fmt.Println(“域注册成功!”)
}否则{
fmt.Println(“注册域失败!”)
}

它是立即死机,还是在一段时间后死机?在一段时间后,大约执行4小时。所以这一定是一个非常具体的场景。是的,这非常适合,我会尝试它,如果这是解决方案,我会在执行后更新。谢谢非常感谢。我会尝试在registerDomain递归调用之前添加return,如果这是个问题,我会更新这篇文章,但我相信这是真的,因为它非常有意义。我已经放心了,因为现在所有的答案(3)都在暗示同样的事情。谢谢-我将尝试并更新。
var result bool
for i := 0; i < 5; i++ {
    result = registerDomain(domainName) // You don't need to pass n anymore
    if result {
        break
    }
}

if result {
    fmt.Println("Domain registered successfully!")
} else {
    fmt.Println("Failed to register domain!")
}