ゴランの熱機能



Golangs Init Function



転載: https://zhuanlan.zhihu.com/p/34211611

golangの主な機能がプログラムのエントリ機能であることは誰もが知っています。 main関数が戻った後、プログラムは終了します。 Golangには、パッケージレベルでいくつかの初期化操作を実装するために、メイン関数の前に実行される別の特別な関数init関数があります。今日は、init機能について詳しく紹介します。



init関数の主な役割:

  • 初期化式で初期化できない変数を初期化します。
  • プログラム実行前の登録。
  • sync.Once関数を実装します。
  • その他

init関数の主な機能:



  • init関数は、main関数の前に自動的に実行され、他の関数から呼び出すことはできません。
  • init関数には、入力パラメーターと戻り値はありません。
  • 各パッケージは複数の初期化関数を持つことができます
  • パッケージの各ソースファイルには、複数のinit関数を含めることもできます。 これはかなり特別です
  • 同じパッケージのinit実行の順序、golangは明確に定義されていません。プログラムは、プログラムがこの実行順序に依存しないことに注意を払う必要があります。
  • さまざまなパッケージのinit関数は、パッケージによってインポートされた依存関係に従って実行順序を決定します。

Golangプログラムの初期化

golangプログラムの初期化は、main関数の前に実行され、ランタイムによって初期化されます。初期化シーケンスは次のとおりです。

  1. インポートされたパッケージを初期化します(パッケージの初期化順序はインポート順序(「上から下」)で実行されません)。ランタイムはパッケージの依存関係を解決する必要があります。依存関係のないパッケージは、変数の初期化依存関係と同様に最初に初期化されます。 。も参照してください golang変数の初期化 );
  2. スコープスコープの変数を初期化します(スコープの変数の初期化は「上から下、左から右」の順序ではなく、ランタイムは変数の依存関係を解決し、依存しない変数が最初に初期化されます。を参照してください。 golang変数の初期化 );
  3. パッケージのinit関数を実行します

例1:



main.go

package main import ( 'fmt' ) var T int64 = a() func init() { fmt.Println('init in main.go ') } func a() int64 { fmt.Println('calling a()') return 2 } func main() { fmt.Println('calling main') }

出力:

calling a() init in main.go calling main

初期化順序: 変数の初期化-> init()-> main()

例2:

pack.go

package pack import ( 'fmt' 'test_util' ) var Pack int = 6 func init() { a := test_util.Util fmt.Println('init pack ', a) }

test_util.go

package test_util import 'fmt' var Util int = 5 func init() { fmt.Println('init test_util') }

main.go

package main import ( 'fmt' 'pack' 'test_util' ) func main() { fmt.Println(pack.Pack) fmt.Println(test_util.Util) }

出力:

init test_util init pack 5 6 5

パックの初期化はtest_utilに依存するため、ランタイムはtest_utilを初期化してから、パッケージを初期化します。

例3:

sandbox.go

package main import 'fmt' var _ int64 = s() func init() { fmt.Println('init in sandbox.go') } func s() int64 { fmt.Println('calling s() in sandbox.go') return 1 } func main() { fmt.Println('main') }

package main import 'fmt' var _ int64 = a() func init() { fmt.Println('init in a.go') } func a() int64 { fmt.Println('calling a() in a.go') return 2 }

z.go

package main import 'fmt' var _ int64 = z() func init() { fmt.Println('init in z.go') } func z() int64 { fmt.Println('calling z() in z.go') return 3 }

出力:

calling a() in a.go calling s() in sandbox.go calling z() in z.go init in a.go init in sandbox.go init in z.go main

異なるソースファイルを使用した同じパッケージのinit関数の実行順序、golang仕様では説明されていません。上記のプログラム出力では、実行順序はソースファイル名の辞書式順序です。

例4:

package main import 'fmt' func init() { fmt.Println('init') } func main() { init() }

init関数を呼び出すことはできません。上記のコードはプロンプトを表示します:undefined:init

例5:

package main import 'fmt' func init() { fmt.Println('init 1') } func init() { fmt.Println('init 2') } func main() { fmt.Println('main') }

出力:

init 1 init 2 main

init関数は特別であり、パッケージ内で複数回定義できます。

例6:

var initArg [20]int func init() { initArg[0] = 10 for i := 1 i

init関数の主な目的:初期化式で初期化できない変数を初期化する

例7:

import _'net / http / pprof '

Golangは、使用されていないインポートされたパッケージのエラーをコンパイルしますが、パッケージのinit関数のみを呼び出し、パッケージによってエクスポートされた変数またはメソッドを使用しない場合があります。次に、上記のインポートスキームを使用します。

上記のインポートが実行された後、init関数は非同期コルーチンを開始してプロセスインスタンスのリソース使用量を収集し、ユーザーにhttpサービスインターフェイスを提供します。