`init` 関数
CoddyのGOジャーニー「論理とフロー」セクションの一部 — レッスン 56/68。
init関数は、パッケージがインポートされたときに自動的に実行されるGoの特別な関数です。通常の関数とは異なり、initを直接呼び出すことはありません。Goがパッケージの初期化プロセス中に自動的に実行します。
init関数の定義方法は以下の通りです:
package mypackage
import "fmt"
func init() {
fmt.Println("Package mypackage is being initialized!")
}init 関数にはいくつかのユニークな特徴があります。パラメータを取らず、値を返さず、main 関数が開始される前に実行されます。これにより、初期状態の設定、コンポーネントの登録、またはパッケージが必要とする一度限りのセットアップタスクの実行に最適です。
init 関数を含むパッケージをインポートすると、そのパッケージのエクスポートされた関数を一切使用しなくても、その効果がすぐに現れます。これが、以前に学んだ空識別子(blank identifier)によるインポートパターンが非常に有用である理由です。これにより、パッケージのコードを直接使用することなく、そのパッケージの初期化をトリガーできます。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
チャレンジ
簡単パッケージがインポートされたときに init 関数が自動的に実行される仕組みを示す、パッケージ初期化システムを作成してください。異なるパッケージが自身を初期化し、その起動シーケンスを追跡するロギングシステムを構築します。
2つの入力を受け取ります:
"package1:message1,package2:message2,package3:message3"という形式のパッケージ定義を含む文字列(例:"database:Database connection pool initialized,cache:Cache system ready,logger:Logging system started")"operation1,operation2,operation3"という形式のメインプログラムの操作を含む文字列(例:"start_server,process_requests,shutdown")
あなたのタスクは以下の通りです:
- 最初の入力をカンマで分割して、個々のパッケージ定義を取得します。
- 各パッケージ定義をコロンで分割して、パッケージ名と初期化メッセージを取得します。
- 初期化メッセージを追跡するための
initLogという名前のグローバルスライスを作成します。 - パッケージ名とメッセージを受け取り、
"[INIT] [%s]: %s"という形式のメッセージをinitLogスライスに追加するlogInitという関数を作成します。 - 入力に現れる順序で各パッケージに対して
logInitを呼び出し、パッケージの初期化をシミュレートします。 - 初期化シーケンスのヘッダーを表示します:
"=== PACKAGE INITIALIZATION SEQUENCE ===" initLogスライスから各初期化メッセージを出力します。- メインプログラムのヘッダーを表示します:
"=== MAIN PROGRAM EXECUTION ===" "All packages initialized successfully"と出力します。- 2番目の入力をカンマで分割して、個々の操作を取得します。
- メインプログラムの各操作について:
"Executing: [operation]"と出力します。- ログにメッセージを追加します:
"[MAIN] Operation: [operation]" - 実行サマリーを表示します:
"=== EXECUTION SUMMARY ===""Packages initialized: [number_of_packages]""Main operations executed: [number_of_operations]""Total log entries: [total_number_of_log_entries]"- 完全なログを表示します:
"=== COMPLETE EXECUTION LOG ==="- 完全なログ(初期化メッセージとメイン操作の両方)の各エントリを出力します。
- 最終メッセージを表示します:
"Program execution completed - all init functions ran before main"
入力文字列の分割には strings パッケージを、フォーマットされた出力には fmt パッケージを使用してください。このチャレンジは、パッケージのインポート中に init 関数が自動的に実行され、常に main 関数の前に実行されることを示しており、パッケージのセットアップや初期化タスクに最適であることを証明します。
チートシート
init 関数は、パッケージがインポートされたときに自動的に実行される Go の特別な関数です:
package mypackage
import "fmt"
func init() {
fmt.Println("Package mypackage is being initialized!")
}init 関数の主な特徴:
- 引数を取らず、値を返しません
- パッケージの初期化中に自動的に実行されます
main関数が開始される前に実行されます- 初期状態の設定や、一度限りのセットアップタスクに最適です
- ブランク識別子(blank identifier)によるインポートでも実行されます
自分で試してみよう
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
// 初期化メッセージを追跡するためのグローバルスライス
var initLog []string
func main() {
reader := bufio.NewReader(os.Stdin)
// 入力を読み込む (bufioはスペースを含む行を正しく処理します)
packageDefs, _ := reader.ReadString('\n')
packageDefs = strings.TrimRight(packageDefs, "\r\n")
mainOps, _ := reader.ReadString('\n')
mainOps = strings.TrimRight(mainOps, "\r\n")
// TODO: 以下にコードを記述してください
// 1. packageDefsを "," で分割して、個々のパッケージエントリを取得する
// 2. 各エントリを ":" で分割し(最大2パート)、packageNameとmessageを取得する
// 3. "[INIT] [packageName]: message" をグローバルなinitLogスライスに追加する
// logInit(packageName, message string) 関数を作成する
// 4. 初期化シーケンスのヘッダーとすべての初期化ログエントリを表示する
// 5. メイン実行ヘッダーを表示し、mainOpsの各操作を処理する
// - 各操作に対して "Executing: <op>" を出力する
// - "[MAIN] Operation: <op>" をinitLogに追加する
// 6. 実行サマリー(パッケージ数、操作数、総ログエントリ数)を表示する
// 7. 完全なログと最終的な完了メッセージを表示する
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。