go语言基础-----03-----流程控制、函数、值传递、引用传递、defer函数

1 流程控制

这里只讲"for range 语句"这个关键字,主要用于遍历,用来遍历数组、slice、map、chan。
例如:

package main

import (
	"fmt"
)

func main() {
	str := "hello world,中国"
	for i, v := range str {
		fmt.Printf("index[%d] val[%c]\n", i, v)
	}
}

在这里插入图片描述

2 函数

函数实际上在上一节也有提过。

2.1. 声明语法:func 函数名 (参数列表) [(返回值列表)] {}

例如

func add(){
}

2.2. golang函数特点:

a. 不支持重载,一个包不能有两个名字一样的函数。
b.函数也是一种类型,一个函数可以赋值给变量。
c. 可以是匿名函数。
d. 多返回值。

函数的例子1,形参带有回调函数。

package main

import "fmt"

// 定义一个函数指针,和C/C++的typedef一样
type op_func func(int, int) int

func add(a, b int) int {
	return a + b
}

func sub(a, b int) int {
	return a - b
}

// 定义一个函数,这个函数的形参带有回调函数
func operator(op op_func, a, b int) int {

	return op(a, b)
}

func main() {
	var a, b int
	add(a, b)

	var c op_func // 自定义类型的变量c。
	c = add       // 将函数赋值给变量c。
	fmt.Println(add)
	fmt.Println(c)

	sum := operator(c, 100, 200)
	fmt.Println(sum)
}

函数的例子2,函数的返回值若只写return,则会按照函数的返回值声明进行返回。

package main

import "fmt"

func calc(a, b int) (sum int, avg int) {
	sum = a + b
	avg = (a + b) / 2
	return // 这里虽然没返回,但是实际上会按照上面的返回值的声明进行返回。相当于语句:return sum, avg
}

func main() {
	sum, avg := calc(10, 20)
	fmt.Println("sum: ", sum, ", avg: ", avg)
}

在这里插入图片描述

2.3. 函数参数传递方式(值传递、引用传递):

1). 值传递。
2). 引用传递。

注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。
并且由于地址拷贝,它们会共用同一片内存,所以在函数内部修改返回后,回到调用函数再进行使用,该变量也是发生变化了的。

注意2:map、slice、chan、指针、interface默认以引用的方式传递。

2.4. 命名返回值的名字

看上面的函数的例子2。

2.5. _标识符,用来忽略返回值

func calc(a, b int) (sum int, avg int) {
	sum = a + b
	avg = (a +b)/2
	return
}

func main() {
	sum, _ := calc(100, 200)
}

2.6. 可变参数:

func add(arg…int) int {					//0个或多个参数
} 
func add(a int, arg…int) int {			// 1个或多个参数
} 
func add(a int, b int, arg…int) int { 	// 2个或多个参数
}

注意:其中arg是一个slice,我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数,但是len(arg)的范围只是arg,不包含已经确定的参数,例如上面代码的"1个或多个参数",前面的a形参是不在这个长度len范围。

例如:

package main

import "fmt"

func add(a int, arg ...int) int {
	var sum int = a
	for i := 0; i < len(arg); i++ {
		sum += arg[i]
	}

	return sum
}

func concat(a string, arg ...string) (result string) {

	result = a
	for i := 0; i < len(arg); i++ {
		result += arg[i]
	}

	return
}

func main() {
	sum := add(10, 3, 3, 3, 3)
	fmt.Println(sum)

	res := concat("hello", " ", "world")
	fmt.Println(res)
}

在这里插入图片描述

3. defer用途:

1. 当函数返回时,执行defer语句。因此,可以用来做资源清理。
2. 多个defer语句,按先进后出的方式执行,与栈的原理一样。
3. defer语句中的变量,在defer声明时就决定了它的值。

3.1 常见清理资源的操作:

// 1 关闭文件句柄:
func read() {
	file := open(filename)
	defer file.Close()
	//文件操作
}

// 2. 锁资源释放
func read() {
	mc.Lock()
	defer mc.Unlock()
	//其他操作
}

// 3. 数据库连接释放
func read() {
	conn := openDatabase()
	defer conn.Close()
	//其他操作
}

3.2 defer的例子1:

package main

import "fmt"

// 定义一个全局的函数变量
var (
	result = func(a1 int, b1 int) int {
		return a1 + b1
	}
)

func test(a, b int) int {
	// 这里定义了一个局部的函数变量,所以实际上test和全局变量result的作用是一样的
	result := func(a1 int, b1 int) int {
		return a1 + b1
	}

	return result(a, b)
}

func main() {
	// 1. 调用全局函数变量
	fmt.Println(result(100, 200))

	var i int = 0

	defer fmt.Println(i)        // 有defer的语句会最后执行,但是用到的变量在这里声明时就决定了,所以这里最后输出:0
	defer fmt.Println("second") // 先进后出,所以两个defer最后必定是输出:second后,再输出 0

	i = 10
	fmt.Println(i)
}

在这里插入图片描述

3.3 例子2:

func f() {
	// 相当于执行了5次defer,然后根据先进后出的情况,那么就是输出 4 3 2 1 0
	for i := 0; i < 5; i++ {
		defer fmt.Printf("%d ", i)
	}
}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值