GO 语言的函数??

news2025/1/15 13:37:19

函数是什么?

学过编程的 xdm 对于函数自然不会陌生,那么函数是什么呢?

函数是一段可以重用的代码块,可以被多次调用,我们可以通过使用函数,提高咱们代码代码的模块化,提高程序的可读性和可维护性

对 GO 语言中的函数,入参可以有多个,返回值也可以有多个,此处建议,入参不大于 5 个,如果超过 5 个最好使用传入结构的方式来进行处理

程序的初始化顺序?

要了解 GO 语言中程序的初始化顺序,就要先明白整个程序初始化流程中,都会涉及到哪一些内容

GO 语言中以包 package 作为 程序逻辑封装的基本单元,每一个包我们可以理解为他是独立的,封装良好的,并且对外暴露了接口的基本单元

然而,咱们的 GO 程序就是由这些包组成的,那么这个包里面一般又包含着 基本的常量,变量,函数,类型,方法,和接口等等

那么对于上述这些元素,我们就要弄明白在包里面他们是如何有序的进行初始化的

本章主要分享函数,GO 语言中除了 main 函数,还有一个特殊的函数就是 init 函数

fun init() {
    // 具体的实现
    // 具体的初始化
}

这里可以看到init 函数,是没有入参,也没有返回值的函数

init 函数用于在本包中进行初始化和做一些程序初始状态的检查工作,例如我们会把一些单例,数据库句柄,各种连接句柄放到 init 函数中进行初始化,init 函数在整个程序生命周期,只会被调用一次

且这里我们需要注意,一个包里面会有多个 GO 语言源文件,这些源文件中都可以定义 init 函数,但是在程序执行 init 函数时,是一个一个的去执行的,而不是并发的去执行的,那么此处的执行顺序我们就不要去过度依赖,按照我们使用惯例来看,过度依赖 init 函数的执行顺序可能会出现意想不到的问题

所以此处我们就需要注意,如果不同的 init 函数实现中,相互有依赖,那么可能就会导致程序出现我们不期望的结果

那么整个程序的初始化流程和顺序我们要知道是这样子的:

对于一个包而言,初始化顺序如下

  1. 包内的包级常量
  2. 包内的包级变量
  3. 包内的 init 函数

对于一个程序里面,从 main 函数开始,必然是包含了其他的子包,那么初始化的时候是怎么样的呢?

  1. 先是初始化子包,若子包里面还有子包,那么就继续从最深一层的子包开始按照包里面的初始化顺序进行
  2. 最深一层的子包按照顺序初始化完毕之后,就到了他的父级包开始按照顺序初始化
  3. 走到 main 包中的 包级常量,包级变量, init 函数进行初始化
  4. 最终,执行 main 函数

通过上图是不是对于 GO 程序初始化顺序更加清晰了呢,如果有表述不当的地方,还请多多评论留言,多多指教

我们可以写一个 demo 来看看效果:

demo 的目录结构如下

main.go 文件的内容如下:

package main

import "fmt"
import _ "ttt/p1"
import _ "ttt/p2"

var (
   _ = checkConst()
   c = varInit(4)
   d = varInit(5)
)

const (
   a = 2
   b = 3
)

func init() {

   fmt.Println("main : init")

}

func checkConst() int {
   if a == 2 {
      fmt.Println("main : const a")
   }
   if b == 3 {
      fmt.Println("main : const b")
   }
   return 0
}

func varInit(x int) int {
   fmt.Println("main : var ", x)
   return x
}

func main() {
   fmt.Println("main : main ")
}
  1. main 包中,我们导入了 p1 和 p2 包,main 包中定义了 const 常量和变量,以及 对应的 init 函数
  2. p1 和 p2 包的内容和 main 的大体一直

运行程序之后,我们可以看到打印的结果如下, 通过这个 demo 我们就可以看到程序的初始化顺序正如上所述

p1 : const a
p1 : const b
p1 : var  4
p1 : var  5
p1 : init
p2 : const a
p2 : const b
p2 : var  4
p2 : var  5
p2 : init
main : const a
main : const b
main : var  4
main : var  5
main : init
main : main

具体的 demo 仓库可以查看如下地址:

GO 语言程序初始化顺序 demo

函数在 GO 语言中的地位?

在 GO 中,我们可以看到没有那些高级语言面向对象的语法,例如 Class 类,继承,对象等等内容, GO 语言中可以通过函数或者方法的方式进行各种组合完成我们想做的一切事项

此处就体现了函数在 GO 语言中是极其的重要,函数在 GO 语言中是 一等公民 的存在

如何体现 一等公民呢?函数在 GO 中可以像普通类型的值一样被创建和被使用,使用起来非常灵活和自由

例如,创建的函数可以存储在变量中,也可以做为其他函数的返回值(在函数内部创建了函数变量之后,通过返回值返回),还可以作为其他函数的参数进行传递

那么我们就来写一些 demo 查看这个 一等公民 是有多么的自由吧:

  1. 正常写一个 函数,简单实现
func helloworld() string{
    name := "阿兵云原生"
    return name
}
  1. 函数作为入参
func add(a, b int) int {
   return a + b
}

func cal(a int, f func(int, int) int) int {
   return a + f(a, a)
}
  1. 函数作为返回值返回出去
func add(a, b int) int {
   return a + b
}

func getFunc() func(int, int) int{
   return add
}
  1. 将函数存储在变量中使用
type TestFunc struct {
   f    func(int, int) int
   name string
}

func add(a, b int) int {
   return a + b
}

func main() {
  
   tt := &TestFunc{f: add, name: "阿兵云原生"}
   fmt.Println(tt.f(1,2))
   
}
  1. 函数作为类型来使用
type PFunc func(int) int

综上所述,对于使用 GO 语言中的函数还是相当方便的,用起来是相当的顺手

那么对于普通类型的数据,我们可以进行显示的类型转换,那么对于函数是不是也可以??

自然是可以的,我们可以来看一个 一般类型的 demo:

var x int = 10
var y int32 = 20
fmt.Println(x + y)

上述代码很明显 x 的类型和 y 的类型是不同的, GO 语言是不会编译通过的,我们需要将其中一个变量的类型显示的转换才可,例如 fmt.Println(int32(x) + t)

再来看看显示转换函数的 demo:

  1. 写一个 Processer 接口,有一个 Do(int) int 接口
  2. 定义一个 PFunc 类型对应 func(int) int
  3. 写一个普通函数和 func playfootball(x int) int
  4. 在 main 函数中,我们直接将 playfootball 赋值给 Processer 看看效果
type Processer interface {
   Do(int) int
}

type PFunc func(int) int

func (f PFunc) Do(x int) int {
   return f(x)
}

func playfootball(x int) int {
   return x
}

func main() {

   var i Processer = playfootball

   fmt.Println(i.Do(20))
}

运行上述代码,很明显是编译不过的,因为 playfootball 的类型和并没有实现 Do 接口,虽然入参和返回值的类型和个数都一样

我们只需要将上述代码,将 playfootball 显示转换,写成 PFunc(playfootball) 即可顺利通过编译,正常看到打印

因为上述 PFunc 类型实现了 Processer 接口,因此对于 i 需要接收的是 PFunc 的实例,这个时候对 playfootball 进行显示转换后,实际上最终调用的函数 playfootball 函数

GO 语言中的 defer

使用过 GO 语言的 xdm 对于 defer 不会陌生,对于那些我们需要在函数退出前释放或者需要关闭的资源,我们就可以使用到 defer 这里用起来就相当的省心,哪怕函数中出现了 panic,defer 也能给你守护的明明白白的

func test() {
   defer func() {
      if e := recover(); e != nil {
         fmt.Println(e)
         fmt.Println("recover ... ")
      }
   }()

   panic("panic ...")
}

func main() {
   test()
}

例如上述 demo ,会正常输出,不会 panic ,因为已经被捕获和处理了

使用 defer 能大大的减少我们的开发人员的心智负担,例如我们以前在使用锁的时候,加锁之后,我们可能会忘记写解锁的语句,可使用了 defer ,你完全可以是在加锁的时候,使用 defer 让函数关闭的时候解锁即可,当然具体逻辑还是要看具体的实现

关于 defer 的原理,以及使用 defer 的注意事项就不在过多赘述,可以查看如下文章获得答案

  1. GO 中的 defer 有哪些注意事项?下
  2. GO 中的 defer 有哪些注意事项?上
  3. GO 中 defer的实现原理

总结:

本次分享了函数相关的基本知识,以及 GO 程序的初始化顺序,对于 defer 的使用有想法的欢迎点击上述连接查看具体 defer 的分享细节

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~
可以进入地址进行体验和学习:https://xxetb.xet.tech/s/3lucCI

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1108346.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

渐进式编程之旅:探寻PHP函数的奇妙世界

目录 前言 一、函数的定义和调用 1.1 初识函数 1.1.1 函数分类 1.1.2 自定义函数 1.1.3 return关键字 1.2 参数设置 1.2.1 无参函数 1.2.2 按值传递参数 1.2.3 引用传参 1.2.4 设置参数默认值 1.2.5 指定参数类型(弱) 1.3 变量的作用域 1.3.1 变量分类 1…

使用bisect模块进行二分查找操作 bisect.bisect()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 使用bisect模块 进行二分查找操作 bisect.bisect() 选择题 请问bisect.bisect(c,2)的结果是: import bisect print("【执行】c [1,2,2,6,7]") c [1,2,2,6,7] print(c…

Linux性能优化--性能追踪3:系统级迟缓(prelink)

12.0 概述 本章包含的例子说明了如何用Linux性能工具寻找并修复影响整个系统而不是某个应用程序的性能问题。阅读本章后,你将能够: 追踪是哪一个进程导致了系统速度的降低。用strace调查一个不受CPU限制的进程的性能表现。用strace调查一个应用程序是如…

清除git历史敏感数据--bfg的应用

项目场景: 开源项目中的git历史中存在敏感 信息,如数据库地址,端口,密码,用户等 我们我们在主分支擦除密码,用户名等,git的历史记录里还是会有相关信息,并不能真正做到清除敏感信息…

前端自学需要把大量时间放在 HTML、CSS 吗?

前言 html和css其实不需要花费太多的时间,html暂且不说,css各类的属性太多了,平时如果只是简单做一些小网站根本不需要全部掌握,只需要掌握一些基础常用的即可,一般遇到不会的也可以直接查文档,就我个人来…

负载均衡、代理和动静分离的战略

一、Nginx简介 1.1 概述 Nginx (“engine x”) 是一个高性能的 HTTP 和 反向代理服务器,特点是占有内存少,并发能力强,能经受高负载的考验,有报告表明能支持高达 50,000 个并发连接数 。 1.2正向代理与反向代理 1.2.1正向代理 正向代理:如果把局域网外的 Internet 想象…

【数之道 06】神经网络模型中激活函数的选择

激活函数的选择 为什么使用激活函数激活函数的选择sigmoidtanhReLU(Rectified Linear Unit)Leaky ReLU( ReLU 函数的变形体)隐藏层的选择顺序 输出层的激活函数以业务要求为导向二分类问题多分类问题多标签问题线性回归问题 b站视频 为什么使用激活函数…

Linux内核8. Linux内核的经典调试方式

1 内核调试以及工具总结 内核总是那么捉摸不透, 内核也会犯错, 但是调试却不能像用户空间程序那样, 为此内核开发者为我们提供了一系列的工具和系统来支持内核的调试. 内核的调试, 其本质是内核空间与用户空间的数据交换, 内核开发者们提供了多样的形式来完成这一功能. 2 用户…

【一】Lambda表达式

1.Lambda表达式概述 ​ Lambda表达式是现代C在C 11和更高版本中的一个新的语法糖 ,在C11、C14、C17和C20中Lambda表达的内容还在不断更新。 lambda表达式(也称为lambda函数)是在调用或作为函数参数传递的位置处定义匿名函数对象的便捷方法。…

BookStack 详解及 Docker-Compose 部署

BookStack 是一款用于创建文档和文档管理的开源平台。它提供了一个直观且功能丰富的界面,可用于组织和管理各种文档,包括文档编写、编辑和共享。本文将介绍 BookStack 的核心功能,并展示如何使用 Docker-Compose 快速部署 BookStack。 BookS…

Qt 窗口常用位置API函数 绘图原理 双缓冲机制 总结

一、Qt 窗口API函数基础知识 在Qt窗口编程中,常用的API函数有: QWidget类的API函数:包括setWindowTitle()、resize()、move()、show()、hide()、setFixedSize()、setWindowFlags()等。 QMainWindow类的API函数:包括setCentralWi…

竞赛选题 深度学习二维码识别

文章目录 0 前言2 二维码基础概念2.1 二维码介绍2.2 QRCode2.3 QRCode 特点 3 机器视觉二维码识别技术3.1 二维码的识别流程3.2 二维码定位3.3 常用的扫描方法 4 深度学习二维码识别4.1 部分关键代码 5 测试结果6 最后 0 前言 🔥 优质竞赛项目系列,今天…

IDEA使用http client无法识别http-client.env.json的环境配置

http-client.env.json的配置 {"dev": {"baseUrl": "http://192.168.60.176:9160","accessToken": "eyJhbPNOQ"} }选择不到环境 问题原因: 安装了Alibaba Cloud Toolkit插件后,被Alibaba Cloud ROS …

vue3中使用百度地图

基本使用 在项目的index.html加入以下代码(记得替换成自己的key) <script type"text/javascript" src"https://api.map.baidu.com/api?v1.0&typewebgl&ak自己的key"></script>在组件中加入以下代码 <template><div id&qu…

CAN通信

通讯方式 UART&#xff1a;(Universal Asynchronous Receiver Transmitter&#xff1a;通用异步收发器/异步串行通信口)&#xff0c;是一种通用的串行数据总线&#xff0c;用于异步通信&#xff0c;支持全双工。它包括了RS232、RS499、RS423、RS422和RS485等接口标准规范和总线…

中文连续视觉语音识别挑战赛

视觉语音识别&#xff0c;也称唇语识别&#xff0c;是一项通过口唇动作来推断发音内容的技术。该技术在公共安全、助老助残、视频验真等领域具有重要应用。当前&#xff0c;唇语识别的研究方兴未艾&#xff0c;虽然在独立词、短语等识别上取得了长足进展&#xff0c;但在大词表…

FCKeditor编辑器漏洞

FCKeditor在网页上属于开发源代码的文字编辑器&#xff0c;FCK是作者的名字 搭建环境 查看版本http://192.168.246.20:89/_whatsnew.html 编辑器界面http://192.168.246.20:89/_samples/default.html 常用上传地址 FCKeditor/editor/filemanager/browser/default/browser.html…

华为云HECS服务器下docker可视化(portainer)

一、docker安装 华为云HECS安装docker-CSDN博客 二、portainer安装 portainer地址&#xff1a;Portainer: Docker and Kubernetes Management Platform 当前portainer分CE&#xff08;开源版&#xff09; 和 BE&#xff08;商业版&#xff09;&#xff0c;用CE即可 1 创建…

聚观早报 | 真我GT5 Pro即将登场;OPPO Find N3即将亮相

【聚观365】10月18日消息 真我GT5 Pro即将登场 OPPO Find N3即将亮相 小米澎湃OS正式版已完成封包 百川智能获3亿美元A1轮融资 理想MEGA实车曝光 真我GT5 Pro即将登场 8月28日&#xff0c;全新的真我GT5正式亮相&#xff0c;该机拥有安卓阵营最强悍的性能配置&#xff0c…

kali使用docker安装DVWA

上一篇文章我记录了如何使用kali安装DVWA&#xff0c;但是我是一个一个组件安装的&#xff0c;非常麻烦&#xff0c;比如数据库还需要配置&#xff0c;花费时间很多。昨天在逛github时&#xff0c;发现大佬的靶场都是通过docker打包好的&#xff0c;如果我也用docker安装DVWA&a…