drvpv7995 2015-01-13 14:55 采纳率: 100%
浏览 78
已采纳

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

Okay, so I have this piece of code

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
}

Explanation:

I call the function with an argument n (let's say 5) that represents the number of times the function will retry if something is not right. Every time something is wrong I make a recursive call with n-1 so when it reaches n=1 it gives up and returns false. This code works fine in practice, it does what it's supposed to do, sometimes when the response is not correct it calls itself recursively and it works the second (or 3rd, 4th..) time around. When the problem isn't fixed before n=1 it returns false.

The problem:

This is a part of a big code that is supposed to run for about 17 hours and it panics when it tries to read from the body sometimes on this line:

bodyBytes, err2 := ioutil.ReadAll(resp.Body)

it says panic: runtime error: invalid memory address or nil pointer dereference. Now I know that probably means that it's trying to read from a nonexistent resp.Body but the Go documentation clearly states that When err is nil, resp always contains a non-nil resp.Body.

So, in my head it's probably something with the recursive calls. The only thing that makes sense to me is this scenario: lets say that the errr is not nil (this means that the resp.Body doesn't exist), so it goes inside of the if errr != nil and because n!=1, it will call itself again with n=4. Let's say this time everything is as it should be and the second function returns true to the first one BUT the first one continues with execution and tries to read from the resp.Body which doesn't exist. That causes panic and here we are...

So, what I need is someone that knows exactly how recursive functions work and if it's not that, can I somehow check the existence of resp.Body before I read form it, or something that will help.

Thanks anyways! :)

UPDATE: You were all right, my code doesn't panic anymore and neither do I. Thank you very much! (I'm not sure if this is where the update goes)

  • 写回答

3条回答 默认 最新

  • douh9817 2015-01-13 15:11
    关注

    Inside the registerDomain() function there are 2 places where you call itself.

    If the client.Do() failes (errr != nil), you will call registerDomain() again. Sometime it will return, and when it does, your code execution will continue, trying to read from resp.Body but that most likely is nil because errr != nil.

    Here is how you should handle it:

    Whenever you make a recursive call, you should not let code continue when that call returns, but return the value it returned, something like this:

    return registerDomain(domainName, n-1)
    

    Alternative

    The problem you're trying to solve can be solved without recursion using a for statement. The for variant will even be clearer and more simple.

    Modify your registerDomain() function to return false at each point it calls itself, and use this loop to retry 5 times:

    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!")
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 python爬取bilibili校园招聘网站
  • ¥30 求解达问题(有红包)
  • ¥15 请解包一个pak文件
  • ¥15 不同系统编译兼容问题
  • ¥100 三相直流充电模块对数字电源芯片在物理上它必须具备哪些功能和性能?
  • ¥30 数字电源对DSP芯片的具体要求
  • ¥20 antv g6 折线边如何变为钝角
  • ¥30 如何在Matlab或Python中 设置饼图的高度
  • ¥15 nginx中的CORS策略应该如何配置
  • ¥30 信号与系统实验:采样定理分析