2

今日、かなり大きなプロジェクトにいくつかの変更を加えましたが、奇妙な動作が発生しています。私はナックルヘッドなので、過去に戻って自分が何をしたかを理解することはできません。

しかし、私の質問の主な目的は、出力されるスタック トレースの負の行番号をどのように理解すべきかということです。以下-1218は私が意味するものです。

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x1 pc=0x80501f2]

goroutine 1 [running]:
server.init()              //     vv-------------RIGHT HERE
    /home/.../debugComponent.go:-1218 +0x282
_/home/.../possessions.init()
    /home/.../possessions.go:29 +0x42
_/home/.../pageWrap.init()
    /home/.../pageWrap.go:112 +0x47

main.init()
    /home/.../main.go:0 +0x3c

goroutine 2 [syscall]:

goroutine 3 [runnable]:

関連debugComponent.goファイルは今のところ重要ではないため、何が起こるかを確認するために削除しました。ファイル名が別の名前と別の負の数に置き換えられました。

このアプリの開発中に多くのバグを見つけなければなりませんでしたが、これで困惑しました。


それが役立つ場合は、main.goいくつかのパッケージが有効です。上記の 3 つのファイルはすべて異なるパッケージであり、これはインポート中に発生しているようです。


ここまで読んでいただけたでしょうか。ここが最も奇妙な部分です。この宣言を に追加するmain.goと、エラーはなくなります!

var test = func() int { return 1 }() // Everything is fine now!

非常に紛らわしいです!やっても治りませんvar test = "foobar"。呼び出された である必要がありますfunc


-1218どんな洞察も高く評価されますが、ほとんどの場合、トレースに興味があります。


アップデート

これを、問題を再現する小さな例に落とし込もうとしています。作業後、元のコードに戻し、マシンを再起動しました。

初めてビルドして実行しようとしたとき、スタック トレースの先頭に 2 つの新しいエントリが追加されました。ただし初回のみ。

goroutine 1 [syscall]:
syscall.Syscall()
    /usr/local/go/src/pkg/syscall/asm_linux_386.s:14 +0x5
syscall.Mkdir(0x83a2f18, 0x2, 0x2, 0x806255e, 0x83a2f1c, ...)
    /usr/local/go/src/pkg/syscall/zerrors_linux_386.go:2225 +0x80
server.init()

したがって、これはスタック トレースの解釈に関する主な質問と一致します。は-1218まだありますが、現在はこれらがあります。

には次のasm_linux_386.s行があり14ます。

MOVL    4(SP), AX       // syscall entry

も見つけましたzerrors_linux_386.goが、線はありません2225。ファイルはその行のずっと前に停止します。

4

2 に答える 2

0

プログラムの実行

インポートのないパッケージは、すべてのパッケージ レベルの変数に初期値を割り当ててから、名前と署名を使用してパッケージ レベルの関数を呼び出すことによって初期化されます。

func init()

そのソースで定義されています。name を持つパッケージ スコープまたはファイル スコープの識別子はinit、このシグネチャを持つ関数としてのみ宣言できます。このような関数は、1 つのソース ファイル内でも複数定義できます。それらは不特定の順序で実行されます。

パッケージ内では、パッケージ レベルの変数が初期化され、参照の順序に従って定数値が決定されます。 の初期化子が にA依存する場合はB、のA後に設定されBます。依存関係の分析は、初期化される項目の実際の値には依存せず、ソースでの外観のみに依存します。の値にの言及が含まれているか、初期化子が を言及している値が含まれているか、または言及している関数を言及しているかAによって異なります。BABBB、再帰的に。このような依存関係が循環している場合はエラーです。2 つの項目が相互に依存していない場合、ソースに表示される順序で初期化されます。コンパイラに提示されるように、複数のファイルである可能性があります。依存関係の分析はパッケージごとに行われるため、Aのイニシャライザが を参照する別のパッケージで定義された関数を呼び出すと、不特定の結果が生じる可能性がありBます。

プログラムのinitどこからでも関数を参照することはできません。特に、明示的に呼び出すことも、ポインターを関数変数に割り当てるinitこともできません 。init

パッケージにインポートがある場合、インポートされたパッケージは、パッケージ自体を初期化する前に初期化されます。複数のパッケージがパッケージ Pをインポートする場合、P一度だけ初期化されます。

パッケージのインポートは、構造上、初期化時に循環的な依存関係がないことが保証されます。

完全なプログラムは、パッケージと呼ばれる単一のインポートされていないパッケージmainを、インポートするすべてのパッケージと推移的にリンクすることによって作成されます。mainパッケージにはパッケージ名が必要であり、引数を取らず値を返さないmain関数を宣言する必要があります。main

func main() { … }

プログラムの実行は、mainパッケージを初期化し、関数を呼び出すことによって開始されますmain。関数mainが戻ると、プログラムは終了します。main他の (非) ゴルーチンが完了するのを待ちません。

パッケージの初期化 (変数の初期化と init関数の呼び出し) は、1 つのゴルーチンで、一度に 1 つのパッケージずつ順番に行われます。init関数は、初期化コードと同時に実行できる他のゴルーチンを起動する場合があります。ただし、初期化は常に関数を順序付けます。前の関数が返されるまでinit、次の関数は開始されません。init

プログラムが実行を開始すると、パッケージ変数が初期化され、init関数が実行されます。パッケージ変数を追加すると、初期化が変更されます。debugComponent.goに関連する何かで初期化に失敗したようserver.init()です。負の行番号はおそらくバグです。

ソースコードがなければ、それ以上のことは言えません。

于 2013-05-31T01:44:51.957 に答える