函数
- 函数的形参列表可以是多个,返回值列表也可以是多个。
- 基本数据类型和数组默认都是值传递的,即进行值拷贝。在函数内修改,不回影响到原来的值。
- 如果希望函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量。
- Go函数不支持传统的重载。
包
包的三大作用:
- 区分相同名字的函数、变量等标识符;
- 当程序文件很多时,可以很好的管理项目
- 控制函数、变量等访问范围,即作用域
包的相关说明
- 打包的基本语法
package 包名
- 引入包的基本语法
import "包的路径" // 路径从src后面开始写
improt(
别名 "包路径"
)
函数递归
函数递归调用需要遵守的重要原则:
- 执行一个函数时,就创建一个新的受保护的独立空间(新函数栈);
- 函数的局部变量是独立的,不会相互影响;
- 递归必须向退出递归的条件逼近,否则就是无限递归;
- 当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁。
package main
import (
"fmt"
)
// 斐波那契数列
func fib(n int) (f int) {
if n <= 2 {
f = 1
} else {
f = fib(n-1) + fib(n-2)
}
return f
}
func main() {
a := fib(4)
fmt.Println(a)
}
函数细节
- 在go中,函数也是一种数据类型
- 在go中,函数可以作为形参,并且调用
- 给数据类型取别名,但go认为别名和原本的数据类型是两个类型,可以应用于函数参数类型
type myInt int
var num myInt
num1 = 40
type myFun func(int,int) int
- Go支持可变参数
1.args是slice切片,通过args[index]可以访问到各个值。
// 支持0到多个参数
func sum(args...int) sum int {
}
// 支持1到多个参数
func sum(n1 int, args ...int) (sum1 int) {
sum1 = n1
for _, val := range args {
sum1 += val
}
return
}
init函数
每一个源文件都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用,也就是说init会在main函数前被调用。
- 如果一个文件同时包含局变量定义、init函数和main函数,则执行的流程是:全局变量定义=>init函数=>main函数
匿名函数
使用方式:
- 在定义匿名函数时就直接调用。
res := func(n1, n2 int) int {
return n2 + n1
}(1, 2)
- 将匿名函数赋值给一个变量(函数变量),再通过该变量来调用匿名函数。
- 全局匿名函数,将匿名函数赋值给一个全局变量,在全局均可调用这个函数。
闭包
func AddUpper() func(int) int {
var n int = 10
return func(x int) int {
n += x
return n
}
}
经典闭包应用
// 给文件加后缀
func makeSuffix(s string) func(string) string {
var suffix string = s
return func(name string) (newName string) {
if strings.HasSuffix(name, suffix) {
newName = name
} else {
newName = name + suffix
}
return
}
}
func main() {
f := makeSuffix(".jpg")
newName := f("www.jpg")
fmt.Println(newName)
}
defer
在函数中,程序员经常需要创建资源(比如:数据库连接、文件句柄、锁等),为了在函数执行完毕后,及时的释放资源,Go的设计者提供defer(延时机制)。
- 当go执行倒一个defer时,不会立即执行defer后的语句,而是将defer后的语句压入倒一个栈中,然后继续执行函数的下一个语句。
- 当函数执行完毕后,再从栈中,依次从栈顶取出语句执行(注:遵守栈,先入后出的机制)。
- 在defer将语句放入栈时,也会将相关的值拷贝同时入栈。
函数参数传递方式
- 值类型:基本数据类型int系列,float系列,bool,string,数组,结构体struct。
- 引用类型:指针,slice切片,map,管道chan,interface等都是引用类型。
其实,不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是,值传递的是值的拷贝,引用传递的是地址的拷贝,一般来说,地址拷贝效率高,因为数据两小,而值拷贝决定拷贝的数据大小,数据越大,效率越低。
内置函数
- len()
- new():new(int)返回一个int指针,*指针可以取到值。(用来分配内存,主要用来分配值类型)
- make():(用来分配内存,主要用来分配引用类型)
- cap(slice):容量
错误处理
- Go中引入的处理方式为:defer,panic,recover
- 这几个异常的使用场景可以这么简单描述:Go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理。
使用defer+recover处理异常
package main
import (
"fmt"
"time"
)
func test() {
defer func() {
err := recover() //recover()内置函数,可以捕获到异常
if err != nil {
fmt.Println("err=", err)
}
}()
num1 := 10
num2 := 0
res := num1 / num2
fmt.Println("res=", res)
}
func main() {
test()
for {
fmt.Println("main()下面代码……")
time.Sleep(time.Second)
}
}
自定义错误
Go程序中,也支持自定义错误,使用errors.New 和panic内置函数。
- errors.New(“错误说明”),会返回一个error类型的值,表示一个错误
- panic内置函数,接受一个interface{}类型的值(也就是任何值了)作为参数。可以接收error类型的变量,输出错误信息,并退出程序。
func readConfig(name string) (err error) {
if name == "config.ini" {
return nil
} else {
// 返回一个自定义错误
return errors.New("读取文件错误")
}
}
func test2() {
err := readConfig("c")
if err != nil {
// 输出错误并终止程序
panic(err)
}
}
版权声明:本文为weixin_38117824原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。