函数的基本使用
函数构成代码执行的逻辑结构。在Go语言中,函数的基本组成为:关键字func、函数名、参数列表、返回值、函数体和返回语句。
函数定义说明:
l func:函数由关键字 func 开始声明
l FuncName:函数名称,根据约定,函数名首字母小写即为private,大写即为public
l 参数列表:函数可以有0个或多个参数,参数格式为:变量名 类型,如果有多个参数通过逗号分隔,不支持默认参数
l 返回类型:
① 上面返回值声明了两个变量名o1和o2(命名返回参数),这个不是必须,可以只有类型没有变量名
② 如果只有一个返回值且不声明返回值变量,那么你可以省略,包括返回值的括号
③ 如果没有返回值,那么就直接省略最后的返回信息
④ 如果有返回值, 那么必须在函数的内部添加return语句
下面通过代码讲述函数的基本使用:
package main
import "fmt"
func sing() {
fmt.Println("i am singing!")
}
func sing2(lrc string) { // 注意不能与sing()函数重名
fmt.Println("i am singing : " + lrc)
}
func sing3(args ...string) { // 注意不能与sing()函数重名
for _, data := range args {
fmt.Println("i am singing : " + data)
}
}
func sing4(args ...string) { // 注意不能与sing()函数重名
sing3(args[:2]...)
}
func sing5(args ...string) { // 注意不能与sing()函数重名
sing3(args[2:]...)
}
func myfunc01() int {
return 666
}
func myfunc02() (result int) { // go语言推荐写法
return 777
}
func myfunc03() (result int) { // go语言推荐写法
result = 888
return
}
func calc(a, b int) (r1, r2 int) { // go语言推荐写法
r1 = a + b
r2 = a * b
return
}
func main() {
fmt.Println("函数的基本使用演示案例")
// 1. 无参数无返回值
sing()
// 2. 有参数无返回值:普通参数列表
sing2("我爱go语言")
// 3. 有参数无返回值:不定参数类型
sing3("A", "B", "C")
sing3("哈哈哈")
sing3()
fmt.Println("==========")
// 4. 不定参数的传递
sing4("x", "y", "z", "666") // x,y
fmt.Println("==========")
sing5("x", "y", "z", "666") // z,666
// 5. 带返回值的函数:有返回值的函数,必须有明确的终止语句,否则会引发编译错误。
res := myfunc01()
fmt.Println("res = ", res)
res2 := myfunc02()
fmt.Println("res2 = ", res2)
res3 := myfunc03()
fmt.Println("res3 = ", res3)
// 6. 函数返回多个返回值
a, b := calc(4, 5)
fmt.Printf("a+b = %d,a*b=%d", a, b)
}
递归函数
package main
import "fmt"
func add(i int) int {
if i == 1 {
return 1
} else {
return i + add(i-1)
}
}
func main() {
fmt.Println("函数的基本使用演示案例")
result := add(100)
fmt.Println("1-100的和是 :", result)
}
函数类型
在Go语言中,函数也是一种数据类型,我们可以通过type来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型。
package main
import "fmt"
func add(a, b int) int {
return a + b
}
func sub(a, b int) int {
return a - b
}
type FuncType func(a, b int) int //没有函数名字,没有函数实体{}
func main() {
fmt.Println("函数类型的使用演示案例")
var calc FuncType
calc = add
r1 := calc(1, 2)
fmt.Println("r1 :", r1)
calc = sub
r2 := calc(8, 2)
fmt.Println("r2 :", r2)
}
回调函数
函数参数是函数类型,这个函数就是回调函数。
package main
import "fmt"
func add(a, b int) int {
return a + b
}
func sub(a, b int) int {
return a - b
}
type FuncType func(a, b int) int //没有函数名字,没有函数实体{}
// 回调函数,函数有一个参数是函数类型,这个函数就是回调函数
func Calc(a, b int, f FuncType) int {
return f(a, b)
}
func main() {
fmt.Println("回调函数的使用演示案例")
m1 := add
r1 := Calc(1, 2, m1)
fmt.Println("r1 = ", r1)
m1 = sub
r1 = Calc(1, 2, m1)
fmt.Println("r1 = ", r1)
}
匿名函数和闭包
所谓闭包就是一个函数“捕获”了和它在同一作用域的其它常量和变量。这就意味着当闭包被调用的时候,不管在程序什么地方调用,闭包能够使用这些常量或者变量。它不关心这些捕获了的变量和常量是否已经超出了作用域,所以只有闭包还在使用它,这些变量就还会存在。
在Go语言里,所有的匿名函数(Go语言规范中称之为函数字面量)都是闭包。匿名函数是指不需要定义函数名的一种函数实现方式,它并不是一个新概念,最早可以回溯到1958年的Lisp语言。
闭包以引用方式捕获外部变量
package main
import "fmt"
func main() {
fmt.Println("匿名函数和闭包的使用演示案例")
a := 10
str := "abc"
///1、匿名函数,没有函数名字,没有函数定义,也没有调用
f1 := func() {
fmt.Printf("a = %d, str = %s\n", a, str)
}
f1()
// 2、给函数类型起别名
type MyFunc func()
var v1 MyFunc
v1 = f1
v1()
//3、有带参数的匿名函数
f2 := func(a, b int) {
fmt.Printf("a = %d, b = %d\n", a, b)
}
f2(3, 4)
// 匿名函数,同时调用
func(a, b int) {
fmt.Printf("a = %d, b = %d\n", a, b)
}(55, 66)
//4、匿名函数,有参数有返回值:
res := func(a, b int) int {
return a + b
}(2, 3)
fmt.Printf("res = %d \n", res)
// 5、闭包:闭包以引用方式捕获外部变量
aa := 10
bb := "abc"
func() {
aa = 20
bb = "zzz"
fmt.Printf("内部 a = %d, b = %s\n", aa, bb) //内部 a = 20, b = zzz
}()
fmt.Printf("外部 a = %d, b = %s\n", aa, bb) //外部 a = 20, b = zzz
fmt.Println("test01 = ", test01()) //1
fmt.Println("test01 = ", test01()) //1
fmt.Println("test02 = ", test02()) //1
fmt.Println("test02 = ", test02()) //1
fmt.Println("test02 = ", test02()) //1
f3 := test02()
fmt.Println("test02 f3 = ", f3()) //1
fmt.Println("test02 f3 = ", f3()) //4
fmt.Println("test02 f3 = ", f3()) //9
//函数test02返回另一个类型为 func() int 的函数。
//对test02的一次调用会生成一个局部变量x并返回一个匿名函数。
//每次调用时匿名函数时,该函数都会先使x的值加1,再返回x的平方。
//第二次调用test02时,会生成第二个x变量,并返回一个新的匿名函数。新匿名函数操作的是第二个x变量。
//通过这个例子,我们看到变量的生命周期不由它的作用域决定:test02返回后,变量x仍然隐式的存在于f中。
}
func test01() int {
var n int
n++
return n * n
}
// 函数返回是一个匿名函数,
func test02() func() int {
var n int
return func() int {
n++
return n * n
}
}
defer的使用
关键字 defer ⽤于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行。注意,defer语句只能出现在函数或方法的内部。
defer语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁。通过defer机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放。释放资源的defer应该直接跟在请求资源的语句后。
package main
import "fmt"
func main() {
fmt.Println("defer的使用演示案例")
fmt.Println("aaaaaaa")
defer fmt.Println("bbbbbbb")
fmt.Println("ccccccc")
// aaa ccc bbb
}
多个defer的调用顺序:
package main
import "fmt"
func main() {
fmt.Println("多个defer的调用顺序使用演示案例")
defer fmt.Println("aaaaaaa")
defer fmt.Println("bbbbbbb")
fmt.Println("ccccccc")
// ccc bbb aaa
}
defer和匿名函数的结合:
package main
import "fmt"
func main() {
fmt.Println("defer和匿名函数的结合使用演示案例")
// 情形一
a := 10
b := "abc"
defer func() {
fmt.Printf("内部:a = %d,b = %s\n", a, b)
}()
a = 20
b = "zz"
fmt.Printf("外部:a = %d,b = %s\n", a, b)
}
defer和匿名函数的结合2:
package main
import "fmt"
func main() {
fmt.Println("defer和匿名函数的结合使用演示案例")
// 情形二
a := 10
b := "abc"
defer func(a int, b string) {
fmt.Printf("内部:a = %d,b = %s\n", a, b) // 内部:a = 10,b = abc
}(a, b)
a = 20
b = "zz"
fmt.Printf("外部:a = %d,b = %s\n", a, b) //外部:a = 20,b = zz
}
获取命令行参数
package main
import "fmt"
import "os"
func main() {
fmt.Println("获取命令行 使用演示案例")
args := os.Args
fmt.Println("len = ", len(args))
for i, data := range args {
fmt.Println("data[%d] = %s", i, data)
}
}
导入包
. 点操作:
package main
// 方式一
// import "fmt"
// import "os"
// 方式二
// import (
// "fmt"
// "os"
// )
// 方式三
import . "os" // 调用函数无需通过包名
import . "fmt"
func main() {
// fmt.Println("导入包使用演示案例")// 如果使用了.操作,则不能这样引用了
// args := os.Args
// fmt.Println("len = ", len(args))
args := Args
Println("len = ", len(args))
}
给包起别名:
package main
import pt "fmt"
import ooss "os"
func main() {
pt.Println("导入包使用演示案例") // 如果使用了.操作,则不能这样引用了
args := ooss.Args
// fmt.Println("len = ", len(args))// err,起完别名之后不能这样使用了
pt.Println("len = ", len(args)) // err,起完别名之后不能这样使用了
}
忽略此包:
import _ "fmt"
其他
过程管理、gopath、init、go install
END.