Go语言8-基本语法-函数

  • 内置函数

函数名 功能
append 把元素添加到slice,返回修改后的slice
copy 复制slice,返回复制的数目
delete 从map中删除key对应的value
panic 停止常规的goroutine
recover 允许程序定义goroutine的panic动作
make 用于slice,map,channel的创建
real 返回complex的实部
imag 返回complex的虚部
new 返回指定类型零值的指针
cap 返回容量(capacity)
close 关闭channel
len 返回 长度
  • 自定义函数

2.1 定义格式

func FuncName(/*参数列表*/)(a type1,b type2/*返回类型*/){
    /*函数体*/
    return v1, v2 //返回多个值
}

注:a.函数由关键字func开始声明,函数声明告诉了编译器函数的名字,返回参数和类型

       b.FuncName即函数名称,根据约定:函数名首字母小写只能再包内使用;大写可以被包外使用;

       c.返回类型:

        1.上面返回值声明了名变量名a和b(命名返回参数),变量名不是必须需要,可以只有类型没有变量名;

        2.如果只有一个返回值且不声明返回值变量,可以省略变量名和返回值的括号,保留变量类型;

        3.如果没有返回值,那么就直接省略最后的返回信息。如果有返回值,那么必须再函数的内部添加return语句。

2.2 函数参数

2.2.1 参数分类

参数 定义 二者关系
形式参数 函数定义中命名的参数 函数调用时,主调函数把实参的值传送给被调函数的形参,从而实现主调函数向被调函数的数据传送。
实际参数 调用有惨函数时,函数名后面括号中的参数

注:a.形参只有在被调用时才分配内存单元,调用结束后,即刻释放所分配的内存单元。

    b.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,再进行函数调用时,他们都必须具有确定的值,以便把这些值传递给形参;

     c.形参和实参在数量上、类型上、顺序上应严格一致,否则会发生类型不匹配的错误;

    d.函数调用中发生的数据传送是单向的,即只能把实参的值传递给形参,而不能把形参的值反向地传递给实参,因此在函数调用过程中,形参的值发生改变,而实参的值不会变化。

2.2.2参数传递

类型 定义
值传递 调用函数时将实际参数复制一份传递到函数中,在函数中对参数进行修改,经不会影响到实际参数。
引用传递 在调用函数时将实际参数的地址(指针)传递到函数中,再函数中对参数所进行的修改,将影响到实际参数

Demo

package main
import "fmt"
func swap1(a1, b1 int) {
    //值传递
    a1, b1 = b1, a1
}
func swap2(c1, d1 *int) {
    //引用传递:c1,d1为指针变量
    *c1, *d1 = *d1, *c1
}
func main() {
    var a int = 2
    var b int = 1
    swap1(a, b)//a,b的值传递给a1,b1
    fmt.Printf("值传递:a = %d, b = %d\n", a, b)
    var c int = 2
    var d int = 1
    swap2(&c, &d)//c,d的地址传递给c1,d1
    fmt.Printf("指针传递:c = %d, d = %d\n", c, d)
}

2.3 自定义函数种类

类型 定义
无参无返回值 既没有传入参数,也没有返回值

有参数,无返回值

(普通参数、不定参数)

有传入的参数,没有返回值

无参有返回值

(一个返回值、多个返回值)

没有传入参数,有返回值的函数
有参有返回值 有传入的参数,有返回值

Demo

package main

import "fmt"

func test1() {
	fmt.Println("无参无返回值")
}

func test2(v1, v2 int) {
	fmt.Printf("有参(普通参数)无返回值:v1=%d, v2=%d\n", v1, v2)
}

func test3(args ...int) { //不定参数,args本质是一个切片
	fmt.Println("有参(不定参数)无返回值:", args)
}

func test4() (value int) {
	value = 250
	return value
}

func test5() (a int, str string) {
	b := 250
	c := "aha"
	return b, c
}
func minAndMax(num1 int, num2 int) (min int, max int) {
	if num1 > num2 {
		min = num2
		max = num1
	} else {
		max = num2
		min = num1
	}
	return
}

func main() {
	test1()
	test2(11, 22)
	test3()
	test3(1)
	test3(1, 2, 3, 4)
	v4 := test4()
	fmt.Println("无参有返回值(一个返回值) ", v4)
	_, v5 := test5()
	fmt.Println("无参有返回值(多个返回值) ", v5)
	min, max := minAndMax(33, 22)
	fmt.Printf("有参有返回值:min = %d, max = %d\n", min, max)
}
  • 变量作用域

类型 定义
局部变量 参数即函数内部定义的变量
全局变量 函数外部定义的变量

a.在同一个作用域内,就近访问最近的变量

b.如果作用域没有声明此变量,则访问全局变量

c.全局变量也没有,则报错

Demo

package main

import "fmt"

var a int

func test01(a float32) {
	fmt.Printf("a type = %T\n", a)
}
func main() {
	fmt.Printf("a type = %T\n", a)
	var a uint8
	fmt.Printf("a type = %T\n", a)
	test01(3.14)
	test02()
}
func test02() {
	fmt.Printf("a type = %T\n", a)
}
  • 匿名函数与闭包

4.1

类型 定义 两者关系
匿名函数 没有定义函数名的函数 在Go语言中所有匿名函数都是闭包
闭包 能够读取其他函数内部常量、变量的函数

a.闭包就是通过匿名函数“捕获”和它在同一作用域的其他常量和变量

b.当闭包被调用的时候,不管再程序什么地方调用,闭包都能 使用这些常量或变量。它不关心这些捕获了的变量和常量是否已经超出了作用域,只要闭包还在使用它,这些变量就会存在。

4.2

定义 描述
直接调用

func(){

}()

声明函数类型后调用

var f1 func()=func(){

}

f1()

自动推导类型

f2:=func(){

}

f2()

直接调用并传参(有参有返回值,

返回值赋值给了一个变量)

v:=func(a,b int)(result int){

result = a+b

return

}(1,1)

Demo

package main

import "fmt"

func square() func() int { //返回值是匿名函数
	var x int
	return func() int { //匿名函数
		x++ //闭包通过此匿名函数“捕获”了函数square()定义的变量x
		return x * x
	}
}

func main() {
	s := square() //square()调用后为一匿名函数,则变量s为匿名函数
	fmt.Println(s())
	fmt.Println(s()) //匿名哈数还在被调用,它内部的变量x仍然没有被释放
	fmt.Println(s())
	fmt.Println(s())
}
  • 函数的延迟调用

5.1 defer的操作使用

序号 描述 示例
1 延迟一个自定义函数的调用 defer A()
2 延迟第三方包中的函数的执行 defer fmt.Pprintln("Hello")
3 延迟匿名函数的调用

defer func(){

    fmt.Println("Hello")

}()

defer 语句只能出现在函数的内部。

Demo

package main

import "fmt"

func main() {
	a, b := 10, 20
	defer func(x int) { // a以值传递方式传给x
		fmt.Println("defer:", x, b) // b闭包引用,由于延迟调用,获取改变和的b
	}(a)
	a += 10
	b += 100
	fmt.Printf("a = %d, b = %d\n", a, b)
}

运行结果:

a = 20, b = 120
defer: 10 120

5.2 多个defer

如果一个函数中有多个defer语句,他们会以LIFO(后进先除)的顺序执行,哪怕函数或某个延迟调用发生错误,这些调用依旧会被执行。

package main

import "fmt"

func test(x int) {
	fmt.Println(100 / x)
}
func main() {
	defer fmt.Println("aaaaaaaa")
	defer fmt.Println("bbbbbbbb")
	defer test(10)
	defer fmt.Println("cccccccc")
}
  • 递归函数

递归函数就是再运行过程中不断地调用自己。

语法格式

func recursion() {
recursion()
}
func main() {
recursion()
}

Demo

阶乘

package main

import "fmt"

func factorial(n int) (result int) {
	if n > 0 { //结束条件,递归必须有终结条件,否则一直递归下去会造成堆栈溢出
		result = n * factorial(n-1)
		return result
	}
	return 1
}
func main() {
	var i = 15
	fmt.Printf("%d的阶乘是: %d\n", i, factorial(i))
}

斐波那契数列

package main

import "fmt"

func fibonacci(n int) int {
	if n < 2 {
		return n
	}
	return fibonacci(n-2) + fibonacci(n-1)
}
func main() {
	var i int
	for i = 1; i < 10; i++ {
		fmt.Printf("%d\t", fibonacci(i))
	}
}

 

你可能感兴趣的:(GO)