Loading

Golang函数

Golang 函数

1、基本概念

为完成某一功能的程序指令(语句)的集合,称为函数

2、语法

func 函数名 (形参列表) (返回值列表) {
    // 执行语句
    
    return 返回值列表
}
  1. 形参列表: 表示函数的输入
  2. 函数中的语句: 表示为了实现某一功能代码块
  3. 函数可以有返回值,也可以没有

3、return 语句

  1. 如果返回多个值时,在接收时,希望忽略某个值时,使用 _ 符号表示占位忽略
  2. 如果返回值只有一个, 返回值类型列表可以不写括号

4、注意事项

4.1、参数个数

函数的形参列表可以是多个,返回值列表也可以是多个

4.2、参数类型

形参列表和返回值列表的数据类型可以是值类型和引用类型。

4.3、作用域

函数的命名遵循标识符命名规范,首字母不能是数字,首字母大写该函数可以被本包文件和其它包文件使用,类似public,首字母小写,只能被本包文件使用,其它包文件不能使用,类似private

4.4、函数内变量

函数中的变量是局部的,函数外不生效

4.5、值传递和引用传递

基本数据类型数组默认都是值传递的,即进行值拷贝。在函数内修改,不会影响到原来的值。

传入变量的地址&,函数内以指针的方式操作变量。

func test(n *int){
    *n = *n + 10
    fmt.Printf("n = %d", *n)
}

func main(){
    n := 20
    // 传入地址
    test(&n)
    fmt.Printf("n = %d", *n)
}

4.6、不支持函数重载

4.7、函数类型

在Go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量了。通过该变量可以对函数调用

fun getSum(n1 int, n2 int) int {
    return n1 + n2
}

func main(){
    
    a := getSum
    // 输出 func getSum(int int) int
    fmt.Printf("a的类型为%T\n", a) 
    
    // 调用函数类型 等价于 getSum(11, 22)
    res := a(11, 22)
    
    // 函数当作形式参数传入
    res = myFun(a, 11, 22)
}

// 带函数类型的形参
func myFun(funvar func(int int) int, num1 int, num2 int) int{
    return funvar(num1, num2)
}

4.8、为了简化数据类型定义,Go支持自定义数据类型

type 自定义数据类型名 数据类型
// 定义一个函数类型
type myFunType func(int, int) int
func myFun2(funvar myFunType, num1 int, num2 int) int {}

4.9、函数返回值命名

func getSumAndSub(n1 int, n2 int) (sum int, sub int){
    // 参数已经定义,直接赋值
    sub = n1 - n2
    sum = n1 + n2
    // 不需要返回值
    return 
}

4.10、忽略返回值

使用_标识符,忽略返回值

4.11、可变参数

1582730151865

package main

import fm "fmt"

func test(n1 int, args ...int) (sum int) {
	sum = n1
	for i := 0; i < len(args); i++ {
		sum += args[i]
	}
	return
}

func main() {
	fm.Println(test(1, 2, 3))
}

5、init 函数

5.1、介绍

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


5.2、注意

  1. 如果一个文件同时包含全局变量定义,init函数和main函数,则执行的流程全局变量定义->init函数->main函数

  2. init函数最主要的作用,就是完成一些初始化的工作

  3. 引入包的init方法先执行

    1582817116341

6、匿名函数

6.1、介绍

Go支持匿名函数,匿名函数就是没有名字的函数,如果我们某个函数只是希望使用一次,可以考虑使用匿名函数,匿名函数也可以实现多次调用。

6.2、创建方式

6.2.1、 直接调用
func main(){
    res = func (n1 int, n2 int) int {
        return n1 + n2
    }(10, 20)
}
6.2.2、赋值给变量
func main(){
    res = func (n1 int, n2 int) int {
        return n1 + n2
    }
    
    a := res
    a(10, 30)
}
6.2.3、全局匿名函数
var (
    fun1 = func (n1 int, n2 int) int {
        return n1 + n2
    }
)

func main(){
    fun1(10, 30)
}

7、闭包

7.1、介绍

闭包就是一个函数与其相关的引用环境组合的一个整体(实体)

7.2、案例

func AddUpper func (int) int {
	var n int = 10
	return func (x int) int {
		n += x
		return n
	}
}
  1. AddUpper是一个函数,返回的数据 类型是fun(int)int
  2. 返回的是一个匿名函数,但是这个匿名函数引用到函数外的n,因此这个匿名函数就和n形成一个整体,构成闭包。
  3. 可理解为: 闭包是类,函数是操作,n是字段。函数和它使用到n构成闭包。
  4. 当我们反复的调用f函数时,因为n是初始化一次,因此每调用一次就进行累计。
  5. 我们要搞清楚闭包的关键,就是要分析出返回的函数它使用(引用)到哪些变量,因为函数和它引用到的变量共同构成闭包。

8、函数的defer

在函数中,程序员经常需要创建资源(比如:数据库连接、文件句柄、锁等),为了在函数执行完毕后,及时的释放资源,Go的设计者提供defer(延时机制)。

8.1、细节

  1. 当go执行到一个defer时,不会立即执行defer后的语句,而是将defer后的语句压入到一个栈中[我为了讲课方便,暂时称该栈为defer栈],然后继续执行函数下一个语句。
  2. 当函数执行完毕后,在从defer栈中,依次从栈顶取出语句执行(注:遵守栈先入后出的机制),所以同学们看到前面案例输出的顺序
  3. 在defer将语句放入到栈时,也会将相关的值拷贝同时入栈

1583247150039

8.2、最佳实战

defer最主要的价值是在,当函数执行完毕后,可以及时的释放函数创建的资源

1583247177314

9、函数参数传递方式

9.1、介绍

值类型参数默认就是值传递,而引用类型参数默认就是引用传递

9.2、方式

1)值传递

2)引用传递其实

不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是,值传递的是值的拷贝,引用传递的是地址的拷贝,一般来说,地址拷贝效率高,因为数据量小,而值拷贝决定拷贝的数据大小,数据越大,效率越低

9.3、值类型和引用类型

1)值类型:

​ 基本数据类型int系列,float系列,bool,string、数组和结构体struct

2)引用类型:

​ 指针、slice切片、map、管道chan、interface等都是引用类型

1583247398564

10、变量作用域

  1. 函数内部声明/定义的变量叫局部变量,作用域仅限于函数内部

  2. 函数外部声明/定义的变量叫全局变量,作用域在整个包都有效,如果其首字母为大写,则作用域在整个程序有效

  3. 如果变量是在一个代码块,比如for/if中,那么这个变量的的作用域就在该代码块

    1583247507898

posted @ 2020-03-03 23:00  TrueBt  阅读(334)  评论(0编辑  收藏  举报