`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 函数的包时,你会立即看到它的效果,即使你没有使用该包导出的任何函数。这就是你之前学过的空白标识符导入模式如此有用的原因:它可以触发包的初始化,而无需直接使用其中的代码。
挑战
简单创建一个包初始化系统,演示导入包时 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")
你的任务是:
- 通过按逗号拆分第一个输入,获取各个包定义
- 对于每个包定义,按冒号拆分,获取包名和初始化消息
- 创建一个名为
initLog的全局切片,用于记录初始化消息 - 创建一个名为
logInit的函数,它接收包名和消息,然后将格式化后的消息"[INIT] [package_name]: [message]"添加到initLog切片中 - 按照包在输入中出现的顺序,为每个包调用
logInit,以模拟包初始化 - 显示初始化顺序标题:
"=== PACKAGE INITIALIZATION SEQUENCE ===" - 打印
initLog切片中的每条初始化消息 - 显示主程序标题:
"=== MAIN PROGRAM EXECUTION ===" - 打印:
"All packages initialized successfully" - 通过按逗号拆分第二个输入,获取各个操作
- 对于主程序中的每个操作:
- 打印:
"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 函数之前运行,因此非常适合用于包设置和初始化任务。
亲手试试
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. 显示完整日志和最终完成消息
}这节课包含一个小测验。开始学习即可作答,并记录你的进度。
逻辑与流程中的所有课
自己练习: Go 在线编译器