Menu
CoddyTech

`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 函数的包时,你会立即看到它的效果,即使你没有使用该包导出的任何函数。这就是你之前学过的空白标识符导入模式如此有用的原因:它可以触发包的初始化,而无需直接使用其中的代码。

challenge icon

挑战

简单

创建一个包初始化系统,演示导入包时 init 函数如何自动执行。你将构建一个日志系统,让不同的包自行初始化,并记录它们的启动顺序。

你会收到两个输入:

  • 一个字符串,包含格式为 "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. 创建一个名为 logInit 的函数,它接收包名和消息,然后将格式化后的消息 "[INIT] [package_name]: [message]" 添加到 initLog 切片中
  5. 按照包在输入中出现的顺序,为每个包调用 logInit,以模拟包初始化
  6. 显示初始化顺序标题:"=== PACKAGE INITIALIZATION SEQUENCE ==="
  7. 打印 initLog 切片中的每条初始化消息
  8. 显示主程序标题:"=== MAIN PROGRAM EXECUTION ==="
  9. 打印:"All packages initialized successfully"
  10. 通过按逗号拆分第二个输入,获取各个操作
  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 函数之前运行,因此非常适合用于包设置和初始化任务。

亲手试试

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. 创建 logInit(packageName, message string) 函数,将
	//    "[INIT] [packageName]: message" 追加到全局切片 initLog 中
	// 4. 显示初始化顺序的标题和所有初始化日志条目
	// 5. 显示主程序执行的标题,并处理 mainOps 中的每个操作
	//    打印每个操作对应的 "Executing: <op>"
	//    将 "[MAIN] Operation: <op>" 追加到 initLog 中
	// 6. 显示执行摘要(包数量、操作数量、日志条目总数)
	// 7. 显示完整日志和最终完成消息

}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

逻辑与流程中的所有课

自己练习: Go 在线编译器