Menu
Coddy logo textTech

`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)によるインポートパターンが非常に有用である理由です。これにより、パッケージのコードを直接使用することなく、そのパッケージの初期化をトリガーできます。

quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

challenge icon

チャレンジ

簡単

パッケージがインポートされたときに 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"

あなたのタスクは以下の通りです:

  1. 最初の入力をカンマで分割して、個々のパッケージ定義を取得します。
  2. 各パッケージ定義をコロンで分割して、パッケージ名と初期化メッセージを取得します。
  3. 初期化メッセージを追跡するための initLog という名前のグローバルスライスを作成します。
  4. パッケージ名とメッセージを受け取り、"[INIT] [%s]: %s" という形式のメッセージを initLog スライスに追加する logInit という関数を作成します。
  5. 入力に現れる順序で各パッケージに対して logInit を呼び出し、パッケージの初期化をシミュレートします。
  6. 初期化シーケンスのヘッダーを表示します:"=== PACKAGE INITIALIZATION SEQUENCE ==="
  7. initLog スライスから各初期化メッセージを出力します。
  8. メインプログラムのヘッダーを表示します:"=== MAIN PROGRAM EXECUTION ==="
  9. "All packages initialized successfully" と出力します。
  10. 2番目の入力をカンマで分割して、個々の操作を取得します。
  11. メインプログラムの各操作について:
    • "Executing: [operation]" と出力します。
    • ログにメッセージを追加します:"[MAIN] Operation: [operation]"
  12. 実行サマリーを表示します:
    • "=== EXECUTION SUMMARY ==="
    • "Packages initialized: [number_of_packages]"
    • "Main operations executed: [number_of_operations]"
    • "Total log entries: [total_number_of_log_entries]"
  13. 完全なログを表示します:
    • "=== COMPLETE EXECUTION LOG ==="
    • 完全なログ(初期化メッセージとメイン操作の両方)の各エントリを出力します。
  14. 最終メッセージを表示します:"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. 完全なログと最終的な完了メッセージを表示する

}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

論理とフローのすべてのレッスン