《Golang入门系列》Golang的函数

Go语言函数

函数是基本的代码块,用于执行一个任务。

Go 语言最少有个 main() 函数。

你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。

函数声明告诉了编译器函数的名称,返回类型,和参数。

函数定义

func function_name( [parameter list] ) [return_types] {
   函数体
}

函数定义解析:

  • func:函数由 func 开始声明
  • function_name:函数名称,函数名和参数列表一起构成了函数签名。
  • parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
  • 函数体:函数定义的代码集合。
func 函数名(形参列表) (返回值列表){
    ...
    return 返回值
}
 
func test0() {
 
}
 
func test1(x int) int{
	return 1
}
 
func test2(x int, y int) (int, int){
	return 1, 2
}
 
func test3(x, y int) (res1 int, res2 int){
	return 1, 2
}
 
func test4(x, y int) (res1 int, res2 int){
	res1 = 1
	res2 = 2
	return
}

函数调用

函数调用非常方便,只要事先导入了该函数所在的包,就可以直接按照如下所示的方式调用函数:

import "mymath"// 假设Add被放在一个叫mymath的包中
// ...
c := mymath.Add(1, 2)

小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用

包使用的注意事项和细节讨论

  • 包名通常是小写字母
  • 要使用其他包的函数的时候,使用import引入该包,包的路径从GOPATH的src下开始的
  • 函数名和变量名的首字母大写才能被访问
  • 访问方式:包名.函数
  • 如果包名过长,可以取别名,但是只能用别名访问
  • 在同一个包下,不能有相同的函数名,或者全局变量名
  • 如果要编译成一个可执行程序文件,就需要将这个包声明为mian,

函数的不定参数

不定参数是指函数传入的参数个数为不定数量。为了做到这点,首先需要将函数定义为接受不定参数类型:

func myfunc(args ...int) {
    for _, arg := range args {
    fmt.Println(arg)
    }
}
 
// 支持如下调用
myfunc(2, 3, 4)
myfunc(1, 3, 7, 13)

形如…type格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数。 从内部实现机理上来说,类型…type本质上是一个数组切片,也就是[]type,这也是为什么上面的参数args可以用for循环来获得每个传入的参数。它是一个语法糖( syntactic sugar),即这种语法对语言的功能并没有影响,但是更方便程序员使用。

不定参数的传递

假设有另一个变参函数叫做myfunc3(args …int), 下面的例子演示了如何向其传递变参:

func myfunc(args ...int) {
    // 按原样传递
    myfunc3(args...)
    // 传递片段,实际上任意的int slice都可以传进去
    myfunc3(args[1:]...)
}

任意类型的不定参数

如果你希望传任意类型,可以指定类型为interface{}。用interface{}传递任意类型数据是Go语言的惯例用法。

函数多返回值

给返回值命名,就像函数的输入参数一样。返回值被命名之后,它们的值在函数开始的时候被自动初始化为空。在函数中执行不带任何参数的return语句时,会返回对应的返回值变量的值。
Go语言并不需要强制命名返回值,但是命名后的返回值可以让代码更清晰,可读性更强,同时也可以用于文档。
如果调用方调用了一个具有多返回值的方法,但是却不想关心其中的某个返回值,可以简单地用一个下划线“_”来跳过这个返回值

func test() (int, int){
	...
}

// 两个返回值都需要
a, b = test()

// 舍去第一个返回值
_, b = test()

匿名函数

在Go里面,函数可以像普通变量一样被传递或使用,这与C语言的回调函数比较类似。不同的是, Go语言支持随时在代码里定义匿名函数。

// 声明一个函数类型
type cb func(int) int

func main() {
    testCallBack(1, callBack)
    testCallBack(2, func(x int) int {
        fmt.Printf("我是回调,x:%d\n", x)
        return x
    })
}

func testCallBack(x int, f cb) {
    f(x)
}

func callBack(x int) int {
    fmt.Printf("我是回调,x:%d\n", x)
    return x
}

闭包

Go 语言支持匿名函数,可作为闭包。匿名函数是一个"内联"语句或表达式。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。

package main

import "fmt"

func getSequence() func() int {
   i:=0
   return func() int {
      i+=1
     return i  
   }
}

func main(){
   /* nextNumber 为一个函数,函数 i 为 0 */
   nextNumber := getSequence()  

   /* 调用 nextNumber 函数,i 变量自增 1 并返回 */
   fmt.Println(nextNumber())
   fmt.Println(nextNumber())
   fmt.Println(nextNumber())
   
   /* 创建新的函数 nextNumber1,并查看结果 */
   nextNumber1 := getSequence()  
   fmt.Println(nextNumber1())
   fmt.Println(nextNumber1())
}

Golang中的函数

init函数

每一个源文件都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用,也就是说init会在main函数前被调用

init函数的注意事项和细节

  1. 如果一个文件同时包含全局变量定义,init函数和main函数,则执行的流程全局变量定义->init函数->main函数
  2. init函数最主要的作用,就是完成一些初始化的工作

函数使用的注意事项和细节讨论

  1. 基本数据类型和数组默认都是值传递,即进行值拷贝
  2. 如果希望函数内的变量能够修改函数外的变量(指的是默认以值传递方式的数据类型),可以传入变量的地址&,函数内以指针的方式操作变量
  3. Go函数不支持函数重载
  4. 在Go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量,通过该变量可以对函数进行调用
  5. 函数是一种数据类型,所以可以作为形参
  6. 自定义数据类型:type 自定义数据类型名 数据类型

你可能感兴趣的:(Golang系列,go)