学习golang(7) 初探:函数(1)

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第26天,点击查看活动详情

虽然编程语言都大相径庭,但是每个语言都还是有一些特性的,所以我们还是要保持空杯心态去看待这件事情,不焦虑,不浮躁,如果觉得自己学到了某些,那么可以将它整理成文档,这也许就是掘金更文的初衷吧。

为什么需要函数

我们可以将一个非常复杂的工作,分为多个子任务,分而治之,不仅如此,假如我们编写一个程序,该程序有n条语句,被多次使用,那么我们有2种调用方法,1. 直接在程序中使用相同的代码 2. 创建一个函数,并在主函数中执行函数即可。还有一个点是,我们使用函数,让多人协作变得更加容易。

为什么我们需要函数?

  • 让多人协作变得很容易
  • 减少没必要的重复代码
  • 提高代码可读性

举个例子:

例如我们在程序中经常输出一些语句fmt.Println("123")这里其实就是函数,只不过它为系统函数,我们为此,不需要重新打印语句,而直接调用即可。

再举个例子:

例如我们想写一个程序,该程序的主要功能为:把大象放进冰箱,那么我们将此划分为三个函数

  • 函数1: 根据大象的体型,找到能够装这么大的并且,并且返回 地址和冰箱门
  • 函数2: 调用函数1,把大象运至该地址
  • 函数3:将大象放入冰箱,并且关闭冰箱门

为此,我们就可以将这个工程,分为三个人,或者三个不同部分协作处理了,每人/每个团队只用根据文档,返回相应的值即可。

函数的调用逻辑

函数调用逻辑概述

函数的调用过程逻辑非常复杂,涉及到了很多底层的东西,我看了一阵子,没怎么学过汇编,我也没怎么看懂,我们来看调用栈的过程吧,

假设 主函数中 调用了函数A,函数A调用了 函数B ,函数B又调用了函数C,那么其调用过程应该为

最先被调用的函数(例如: main) 最后被执行完毕

最后被调用的函数(C)最先被执行完毕

尝试使用调试工具分析调用逻辑

我们虽然暂时还看不懂,汇编的东西,但是我们可以debug一下函数调用栈

操作步骤

  • layout src显示源代码窗口
  • l查看代码
  • 使用b设置断点
  • 使用run运行代码
  • 使用c切换到端点
  • 使用bt查看调用栈

如图,我们能够清楚的看到函数调用栈:

main函数最先入栈,最后一个出栈,而c函数最后入栈,却最先出栈。

函数的基本使用

函数格式

go函数格式如下

func 函数名称(函数参数列表) (返回值列表) {
    ...
}
复制代码

例如我们写一个返回程序,该程序有一个函数add1 ,add1接收一个int的参数,并且返回该参数-1的值

函数定义如下

func add1(x int)(int) {
	return x-1
}
复制代码

我们执行该程序

返回多个值

我们可以使用go返回多个值,还记得之前我们写的tcp服务器 么? 其中就返回了多个值

语法如下

func 函数名称(参数)(返回类型A,返回类型B) {
}
复制代码

我们来尝试下

我们改写下程序,将原参数-1 和 原参数 的值返回回去

我们执行一下语句

不仅如此,我们还可以隐式返回,我们修改下代码

我们在函数返回上定义变量,然后赋值起变量,最后使用return,此语句也会返回2个参数,不过一般用的不是很多

我们执行下

以上就是函数的基本使用,简单吧,是不是和其他语言差不多。

go函数的特性

除了和别的语言差不多的函数声明,go还提供了其他的函数申明,来看下

匿名函数

我们再func后没有添加函数名称,这个称之为匿名函数,我们可以将上述例子修改为匿名函数的形式

我们执行下代码

什么时候会用到匿名函数呢?

我们若仅在某个时刻使用该函数一次,后面我们就不用了,我们则可以使用匿名函数,比如,我们利用协程处理事情

我们执行下

defer代码

我们进程在go中看到defer, 其实它的作用为: 在函数结束完毕后,执行defer语句(不管函数是否正常都会执行defer)

例如,我们有如下代码

从上述我们可以知道,defer是在return结束完毕后再执行的,具体的我们执行下代码看看

还有一点,若我们在写defer之前,程序就崩溃了,此时是不会调用defer语句的,例如

我们执行下代码

总结

go因为没有try,所以,我们判断是否正常,就很需要函数返回正常的值,和error,我们再判断error是否为nil,若为nil则代表函数执行成功,否则执行出错。

此外,defer真的很强大,在别的语言中,我们一般打开一个文件,都会在最后关掉句柄,虽然go有回收机制,但是回收机制,一般用于在程序中申请的变量,不包括打开的系统资源,所以,我们可以在打开后,设置defer关闭文件,这样绝不会出错,例如

fs , err := os.Open("123.txt")
if err != nil {
        return
}
defer fs.Close()
复制代码

今天就这样吧,今天学gdb花了太多时间了。,以前没怎么用gdb调试过,我一般调试代码还没有达到栈级别,都是使用打印大法print调试的。

溜了 溜了

猜你喜欢

转载自juejin.im/post/7090832247296622605