这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记

93 阅读3分钟

3 函数

3.1 函数的定义

在Golang的函数定义中,所有的函数都以func开头,并且Golang命名推荐使用驼峰命名法。

注意,在Golang的函数中,如果首字母是小写,则只能在包内使用;如果首字母是大写,则可以在包外被引入使用。可以理解为,使用小写的函数,是private的,使用大写的函数,是public的。

在Golang的函数定义中,一样可以不接受参数,或者接受多个参数。而在参数的定义过程中,也是按照定义变量的格式,先定义变量名,再声明变量类型。对于函数的返回类型,也是按照这样的格式,先写函数名,再写返回类型:

        return x + y 
  } 
  func main() { 
      fmt.Println(add(42, 13)) 
  }

并且,对于相同类型的两个参数,参数类型可以只写一个,用法如下:

func add(x, y int) int {
    return x + y 
}

在Golang中,对于函数的返回值,和C以及Java是不一样的。 Golang中的函数可以返回任意多个返回值。 例如下面的例子:

func swap(x, y string) (string, string) { 
    return y, x 
    }
    
func main() { 
    a, b := swap("hello", "world") 
    fmt.Println(a, b)
 }

其次,函数的返回值是可以被命名的:

func split(sum int) (x, y int) {
	x = sum * 4 / 9
	y = sum - x
	return
}


在这里,我们可以理解为在函数的顶部预先定义了这些变量值,而空的return语句则默认返回所有已经定义的返回变量

3.2defer

在Golang中,有一个关键字叫defer。

defer 语句会将函数推迟到外层函数返回之后执行。 推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。

func main() {
	defer fmt.Println("world")

	fmt.Println("hello")
}

在这段代码中,本来的执行路径是从上往下,也就是先输出“world”,然后再输出“hello”。但是因为defer这个关键字的存在,这行语句将在最后才执行,所以产生了先打印“hello”然后再打印“world”的效果。

注意,defer后面必须是函数调用语句,不能是其他语句,否则编译器会报错。

可以考虑到的场景是,文件的关闭,或数据库连接的释放等,这样打开和关闭的代码写在一起,既可以使得代码更加的整洁,也可以防止出现开发者在写了长长的业务代码后,忘记关闭的情况。

至于defer的底层实现,本文不进行详细的解释,简单来讲就是将defer语句后面的函数调用的地址压进一个栈中,在当前的函数执行完毕,CPU即将执行函数外的下一行代码之前,先把栈中的指令地址弹出给CPU执行,直到栈为空,才结束这个函数,继续执行后面的代码。

从上文刚刚的表述中也可以推断出,如果有多条refer语句,将会从下往上依次执行。

因为本文只是对各种指令简单的进行对比,所以对于refer的详细解释,将在以后的文章中详细说明。