2

さて、私はこのコードを持っています

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 を返します。このコードは実際には問題なく動作し、本来の動作を行います。応答が正しくない場合は、再帰的に自分自身を呼び出し、2 回目 (または 3 回目、4 回目..) に動作します。n=1 になる前に問題が修正されない場合は、false を返します。

問題:

これは、約 17 時間実行されるはずの大きなコードの一部であり、次の行で本文から読み取ろうとするとパニックになります。

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

パニック: ランタイム エラー: 無効なメモリ アドレスまたは nil ポインター逆参照と表示されます。これはおそらく、存在しない resp.Body から読み取ろうとしていることを意味していることがわかりましたが、Go のドキュメントには、 err が nil の場合、 resp には常に nil 以外の resp.Body が含まれていると明確に記載されています。

だから、私の頭の中では、おそらく再帰呼び出しを伴うものです。私にとって理にかなっている唯一のことは、このシナリオです: エラーが nil ではない (これは resp.Body が存在しないことを意味します) としましょう。 1 の場合、n=4 で再び自分自身を呼び出します。今回はすべてが正常で、2 番目の関数が最初の関数に true を返しますが、最初の関数は実行を続行し、存在しない resp.Body から読み取ろうとするとしますそれはパニックを引き起こし、ここにいます...

だから、私が必要としているのは、再帰関数がどのように機能するかを正確に知っている人です。

とにかく、ありがとう!:)

更新:大丈夫でした。私のコードはもうパニックにならず、私もそうではありません。どうもありがとうございました! (ここがアップデートの対象かどうかはわかりません)

4

3 に答える 3

3

変化する

registerDomain(domainName, n-1)

return registerDomain(domainName, n-1)

このようにして、外部関数は実行を継続せず、nil 本体から読み取ることはありません。

于 2015-01-13T15:10:20.673 に答える
2

関数内には、registerDomain()自分自身を呼び出す場所が 2 つあります。

失敗した場合client.Do()( errr != nil)、registerDomain()再度呼び出します。いつかそれが返され、返されると、コードの実行が続行され、から読み取ろうとしますが、それresp.Bodyはおそらく.nilerrr != nil

対処方法は次のとおりです。

再帰呼び出しを行うときはいつでも、その呼び出しが戻ったときにコードを続行させずに、次のような戻り値を返す必要があります。

return registerDomain(domainName, n-1)

for解決しようとしている問題は、ステートメントを使用して再帰なしで解決できます。バリアントはさらに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!")
}
于 2015-01-13T15:11:13.463 に答える
1

最初の 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)
}
于 2015-01-13T15:10:16.010 に答える