【Go 基础篇】Go语言 init函数详解:包的初始化与应用
介绍
在Go语言中,init()
函数是一种特殊的函数,用于在包被导入时执行一次性的初始化操作。init()
函数不需要手动调用,而是在包被导入时自动执行。这使得我们可以在包导入时完成一些必要的初始化工作,确保包的使用具有正确的环境和状态。
本篇博客将深入探讨 init()
函数的作用、调用时机、使用方式以及一些实际应用场景。通过理解和掌握 init()
函数,您将能够更好地利用它来进行包的初始化和配置,提高代码的可维护性和可靠性。
init()
函数的基本概念
作用与调用时机
init()
函数是一种在Go语言中用于执行初始化操作的特殊函数。每个包可以包含多个 init()
函数,它们会在包被导入时按照顺序自动执行。init()
函数的调用时机为:
- 当包被导入时,
init()
函数会按照导入的顺序自动执行。 - 同一个包中的多个
init()
函数按照编写的顺序执行。
需要注意的是,虽然 init()
函数在包被导入时自动执行,但它们并不会被外部调用。这与其他函数不同,其他函数需要显式地被调用才能执行。
使用方式
init()
函数的使用方式相对简单,它的定义和普通函数类似,只是函数名为 init
。init()
函数没有参数和返回值,不需要手动调用,而是在包被导入时自动执行。
package mypackageimport "fmt"func init() {fmt.Println("mypackage 初始化")
}
在上面的示例中,当 mypackage
包被导入时,会自动执行 init()
函数,输出 “mypackage 初始化”。
init()
函数的应用场景
初始化配置信息
init()
函数常用于初始化包的配置信息。例如,当包提供某些服务时,可以在 init()
函数中读取配置文件,进行初始化设置,以便服务能够在正常环境下运行。
package configimport ("fmt""os"
)var Config map[string]stringfunc init() {// 读取配置文件,初始化 Config 变量configFile := "config.ini"Config = make(map[string]string)file, err := os.Open(configFile)if err != nil {fmt.Println("配置文件读取失败:", err)return}defer file.Close()// 将配置信息解析到 Config 变量中// ...
}
数据库初始化
在一些应用中,数据库的初始化通常在包被导入时进行。init()
函数可以用于建立数据库连接,进行必要的数据表创建等操作。
package databaseimport ("database/sql"_ "github.com/go-sql-driver/mysql"
)var DB *sql.DBfunc init() {// 建立数据库连接var err errorDB, err = sql.Open("mysql", "username:password@tcp(localhost:3306)/mydb")if err != nil {panic("数据库连接失败:" + err.Error())}// 创建数据表_, err = DB.Exec(`CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50),email VARCHAR(50))`)if err != nil {panic("数据表创建失败:" + err.Error())}
}
注册功能插件
某些情况下,包中可能存在多个功能插件,这些插件需要在包被导入时注册到主程序中。init()
函数可以用于执行插件的注册操作。
package pluginvar plugins []func()func init() {plugins = append(plugins, func() {// 注册插件1的功能})plugins = append(plugins, func() {// 注册插件2的功能})
}func RunPlugins() {for _, p := range plugins {p()}
}
在上述示例中,init()
函数用于注册两个插件的功能,然后通过 RunPlugins()
函数执行已注册的插件。
init()
函数的注意事项
虽然 init()
函数是方便的初始化工具,但也需要注意一些事项:
执行顺序
同一个包中的多个 init()
函数按照编写的顺序依次执行。在导入包时,它们的调用顺序与导入顺序相同。
不应该被调用
init()
函数不需要手动调用,它会在包被导入时自动执行。不应当在代码中尝试显式调用 init()
函数。
不能返回值
init()
函数不能有返回值,其返回值会被忽略。这与其他函数不同,其他函数的返回值是可以被接收和使用的。
避免过于复杂的操作
尽管可以在 init()
函数中执行一些初始化操作,但应当避免过于复杂和耗时的操作,以免影响导入包的性能和效率。
总结
init()
函数是Go语言中一种特殊的函数,用于在包被导入时执行一次性的初始化操作。它的作用范围广泛,可以用于初始化配置信息、建立数据库连接、注册功能插件等。通过理解和应用 init()
函数,我们可以在包被导入时执行必要的初始化工作,提高代码的可维护性和可靠性。
在使用 init()
函数时,需要注意它的调用时机、使用方式以及一些注意事项。合理地利用 init()
函数,能够在项目中实现更灵活、更模块化的初始化和配置流程。
不同包的 init()
函数执行顺序是由导入顺序决定的,这意味着如果一个包的初始化依赖于另一个包,确保正确的导入顺序是很重要的。避免循环导入,确保包之间的依赖关系是合理的,这可以保证 init()
函数的执行顺序是按照预期的。
尽管 init()
函数可以执行一些必要的初始化操作,但应当避免在其中进行过于复杂和耗时的操作。因为 init()
函数会在包被导入时自动执行,如果执行过程太复杂,可能会影响导入的性能和效率。应当将复杂的操作放在真正需要的地方,以保持 init()
函数的简洁性和高效性。
对于全局变量的初始化,init()
函数也是一个很好的选择。通过在 init()
函数中初始化全局变量,可以确保它们在包被导入时具有正确的初始值,避免在使用时出现未初始化的情况。
在一些情况下,init()
函数可以用于实现一些类似单例模式的功能。通过在 init()
函数中进行一次性的初始化,可以保证在整个程序生命周期中只有一个实例被创建。
总之,init()
函数是Go语言中用于包的初始化操作的重要工具。它使得在包被导入时执行初始化操作变得非常方便,有助于提高代码的可维护性和稳定性。在使用 init()
函数时,应当注意其调用顺序、避免复杂操作、合理利用全局变量的初始化以及保持代码的简洁性。通过合理地应用 init()
函数,您可以更好地管理包的初始化和配置,为项目开发提供更强大的支持。
相关文章:
【Go 基础篇】Go语言 init函数详解:包的初始化与应用
介绍 在Go语言中,init() 函数是一种特殊的函数,用于在包被导入时执行一次性的初始化操作。init() 函数不需要手动调用,而是在包被导入时自动执行。这使得我们可以在包导入时完成一些必要的初始化工作,确保包的使用具有正确的环境…...

wazuh环境配置及漏洞复现
目录 一、wazuh配置 1进入官网下载OVA启动软件 2.虚拟机OVA安装 二、wazuh案例复现 1.wazuh初体验 2.这里我们以SQL注入为例,在我们的代理服务器上进行SQL注入,看wazuh如何检测和响应 一、wazuh配置 1进入官网下载OVA启动软件 Virtual Machine (O…...

Java接收前端请求体方式
💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! 文章目录 RequestBodyPathVariableRequestParamValidated方法参数校验方法返回值校验 RequestHeaderHttpServletRequest ## Java接收前端请求体的方式 请求体…...

私有化部署即时通讯平台,30分钟替换钉钉和企业微信
随着企业对即时通讯和协作工具的需求不断增长,私有化部署的即时通讯平台成为企业的首选。WorkPlus作为有10余年行业深耕经验与技术沉淀品牌,以其安全高效的私有化部署即时通讯解决方案,帮助企业在30分钟内替换钉钉和企业微信。本文将深入探讨…...

如何深入理解 Node.js 中的流(Streams)
Node.js是一个强大的允许开发人员构建可扩展和高效的应用程序。Node.js的一个关键特性是其内置对流的支持。流是Node.js中的一个基本概念,它能够实现高效的数据处理,特别是在处理大量信息或实时处理数据时。 在本文中,我们将探讨Node.js中的流…...

MSP430FR2xxx开发(一)添加driverlib
一、新建工程 根据自己手上的硬件型号新建工程,文中已MSP430FR2355为例。 二、添加driverlib 首先去官方下载driverlib. https://www.ti.com.cn/tool/cn/MSPDRIVERLIB?keyMatchMSP430%20DRIVERLIB#downloads 下载后的内容如下: 我这里就选择MSP430…...

【C++】做一个飞机空战小游戏(九)——发射子弹的编程技巧
[导读]本系列博文内容链接如下: 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…...
34.SpringMVC获取请求参数
SpringMVC获取请求参数 通过ServletAPI获取 将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象 index.html <form th:action"{/test/param}" method"post">用户名&#…...

TC1016-同星4路CAN(FD),2路LIN转USB接口卡
TC1016是同星智能推出的一款多通道CAN(FD)和LIN总线接口设备,CANFD总线速率最高支持8M bps,LIN支持速率0~20K bps,产品采用高速USB2.0接口与PC连接,Windows系统免驱设计使得设备具备极佳的系统兼容性。 支…...
Android源码——从Looper看ThreadLocal
1 概述 ThreadLocal用于在当前线程中存储数据,由于存储的数据只能在当前线程内使用,所以自然是线程安全的。 Handler体系中,Looper只会存在一个实例,且只在当前线程使用,所以使用ThreadLocal进行存储。 2 存储原理 …...

16、Flink 的table api与sql之连接外部系统: 读写外部系统的连接器和格式以及JDBC示例(4)
Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…...
MySQL 自定义 split 存储过程
MySQL 没有提供 split 函数,但可以自己建立一个存储过程,将具有固定分隔符的字符串转成多行。之所以不能使用自定义函数实现此功能,是因为 MySQL 的自定义函数自能返回标量值,不能返回多行结果集。 MySQL 8: drop pr…...

专题-【十字链表】
有向图的十字链表表示法:...
微信小程序教学系列(2)
第二章:小程序开发基础 1. 小程序页面布局与样式 在小程序开发中,我们可以使用 WXML(WeiXin Markup Language)和 WXSS(WeiXin Style Sheet)来定义页面的布局和样式。 1.1 WXML基础 WXML 是一种类似于 H…...
社科院与美国杜兰大学金融管理硕士项目——畅游于金融世界
随着社会经济的不断发展,职场竞争愈发激烈,很多同学都打算通过报考研究生来实现深造,提升自己的综合能力和竞争优势,获得优质的证书。而对于金融专业的学生和在职人员来说,社科院与美国杜兰大学金融管理硕士项目是一个…...

功能强大、超低功耗的STM32WL55JCI7、STM32WL55CCU7、STM32WL55CCU6 32位无线远距离MCU
STM32WL55xx 32位无线远距离MCU嵌入了功能强大、超低功耗、符合LPWAN标准的无线电解决方案,可提供LoRa、(G)FSK、(G)MSK和BPSK等各种调制。STM32WL55xx无线MCU的功耗超低,基于高性能Arm Cortex-M4 32位RISC内核(工作频率高达48MHz)…...

【自适应稀疏度量方法和RQAM】疏度测量、RQAM特征、AWSPT和基于AWSPT的稀疏度测量研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

sql递归查询
一、postgresql 递归sql with recursive p as(select t1.* from t_org_test t1 where t1.id2union allselect t2.*from t_org_test t2 join p on t2.parent_idp.id) select id,name,parent_id from p; sql中with xxxx as () 是对一个查询子句做别名,同时数据库会对…...

常见前端面试之VUE面试题汇总三
7. Vue 中封装的数组方法有哪些,其如何实现页面更新 在 Vue 中,对响应式处理利用的是 Object.defineProperty 对数据进 行拦截,而这个方法并不能监听到数组内部变化,数组长度变化,数 组的截取变化等,所以需…...

Three.js 实现模型材质分解,拆分,拆解效果
原理:通过修改模型材质的 x,y,z 轴坐标 positon.set( x,y,z) 来实现拆解,分解的效果。 注意:支持模型材质position 修改的材质类型为 type“Mesh” ,其他类型的材质修改了position 可能没有实际效果 在上一篇 Three.js加载外部glb,fbx,gltf…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...