golang学习笔记第二部分:6.函数

13、函数

  • 定义:为完成某功能的程序指令(语句)的集合,称为函数
  • 在go中,函数分为:自定义函数、系统函数

基本语法

func 函数名(形参列表) (返回值列表){ 执行语句 return 返回值列表 }

包的概念和使用

包的本质实际是创建不同的文件夹来管理程序 go的每一个文件都是必须属于一个包 包里的函数名首字母大写才可以被其他包调用 注意细节: 1)包名一般和文件夹名相同,尤其是有IDE插件时 2)使用其他包的函数或变量时,需要先引入
3)package在第一行,然后才是import 4)import时,路径从$GOPATH的src开始查找 5)包可以起别名,替换原有的包名 6)同一个包里函数名、全局变量名不能重复 7)如果要编译,需要有一个包声明为main: go
build l6/d1/main -o xxx.exe,编译过程中会生成库文件

函数的调用

多个返回值时,如果有某个不需要,可以用 _ 接收 返回值只有一个时,返回列表不需要()

函数的递归调用

一个函数在函数体内又调用了本身,称为递归调用 注意:递归必须向退出条件逼近,否则就是无限循环

函数的形参列表中使用可变参数时,需要放在形参的最后位置 args

init函数:构建函数,在main()函数前调用 如果一个文件同时包含全局变量定义、init、main函数,则执行顺序是:全局变量定义->init->main 如果包里和main.go都有init,引入后执行的顺序是:包里的变量定义->
包里的init->main的变量定义->main的init->main()

package main

import (
	"fmt"
	"code/utils"
)

func getSumAndSub(n1 int, n2 int) (int, int) {
	sum := n1 + n2
	sub := n1 - n2
	return sum, sub
}

func test(n int) {
	if n > 2 {
		n--
		test(n)
	}
	fmt.Printf("n=%v\n", n)
}

func test2(n int) {
	if n > 2 {
		n--
		test2(n)
	} else {
		fmt.Printf("n=%v\n", n)
	}
}

//斐波那契数列
//当n==1||n==2时,返回1
//当n>2,返回前面2个数的和 f(n-1)+f(n-2)
func fbn(n int) int {
	if n == 1 || n == 2 {
		return 1
	} else {
		return fbn(n-1) + fbn(n-2)
	}
}

//可变参数的使用
func sum(n1 int, args ...int) int {
	sum := n1
	for i := 0; i < len(args); i++ {
		sum += args[i]
	}
	return sum
}

func swap(n1 *int, n2 *int) {
	t := *n1
	*n1 = *n2
	*n2 = t
}

func main() {
	// a := utils.calc(11.2, 42.1, '+')
	b := utils.Calc2(3.2, 1.3, '/')
	fmt.Printf("结果是%.2f\n", b) //格式化输出小数点后2位
	res1, res2 := getSumAndSub(3, 5)
	fmt.Printf("两个数的和是%v,差是%v\n", res1, res2)
	res3, _ := getSumAndSub(4, 6)
	fmt.Printf("两个数的和是%v\n", res3)
	test(4)  //test(4) test(3) test(2) 输出3次
	test2(4) //test2(2)走到else里,输出1次
	for i := 1; i <= 20; i++ {
		m := fbn(i)
		fmt.Printf("%v,", m)
	}
	res4 := sum(1, 2, 3, 4, 5)
	fmt.Println("res4=", res4)
	x := 10
	y := 20
	swap(&x, &y)
	fmt.Printf("x=%v,y=%v", x, y)
}
package utils

import "fmt"

//小写字母开头的函数,不能被其他包调用
func calc(n1 float64, n2 float64, operator byte) float64 {
	var res float64
	switch operator {
	case '+':
		res = n1 + n2
	case '-':
		res = n1 - n2
	case '*':
		res = n1 * n2
	case '/':
		res = n1 / n2
	default:
		fmt.Println("操作符错误")
	}
	return res
}

//大写字母开头,可以调用
func Calc2(n1 float64, n2 float64, operator byte) float64 {
	var res float64
	switch operator {
	case '+':
		res = n1 + n2
	case '-':
		res = n1 - n2
	case '*':
		res = n1 * n2
	case '/':
		res = n1 / n2
	default:
		fmt.Println("操作符错误")
	}
	return res
}

匿名函数:没有命名的函数,如果某个函数只是希望使用一次,可以使用匿名函数

可以定义时直接调用、赋值给一个变量 如果将匿名函数赋值给全局变量,那么该函数成为全局匿名函数

package main

import "fmt"

var Fun1 = func(n1 int, n2 int) int {
	return n1 * n2
}

func main() {
	//匿名函数
	res := func(n1 int, n2 int) int {
		return n1 + n2
	}(10, 2)

	fmt.Printf("res=%v\n", res)
	//将匿名函数赋值给变量a
	a := func(n1 int, n2 int) int {
		return n1 - n2
	}
	fmt.Printf("a=%v\n", a(20, 3))
	fmt.Printf("f=%v\n", Fun1(3, 4))
}

闭包:一个函数与其相关的引用环境组合的一个实体

package main

import (
	"fmt"
	"strings"
)

//累加器
//addupper返回的数据类型是func(int)int匿名函数,引用到了函数外的变量n,这组成了一个闭包
func AddUpper() func(int) int {
	var n int = 10
	var str = "a"
	return func(x int) int {
		n = n + x
		str += "x"
		fmt.Println("str=", str)
		return n
	}

}

func exec1() {
	f := AddUpper()
	//当我们重复调用AddUpper函数时,因为n是初始化一次,因此每次结果会累加,而不会重新初始化n
	//关键一点是需要分析出函数使用到哪些变量
	fmt.Printf("addupper=%v\n", f(1))
	fmt.Printf("addupper=%v\n", f(1))
	fmt.Printf("addupper=%v\n", f(1))
}

//接收一个文件后缀名,并返回一个闭包
//调用闭包,可以传入一个文件名,如果没有指定后缀,则加上,如果有,则返回文件名
func makeSuffix(suffix string) func(string) string {
	//返回的匿名函数和suffix变量组成闭包
	return func(name string) string {
		if strings.HasSuffix(name, suffix) == false {
			return name + suffix
		}
		return name
	}
}

//闭包对比一般函数的写法,.jpg只需要传入一次,一般函数需要每次都传入.jpg参数
func makeSuffix2(suffix, name string) string {
	//一般函数的写法,也能实现

	if strings.HasSuffix(name, suffix) == false {
		return name + suffix
	}
	return name

}

func exec2() {
	f := makeSuffix(".jpg")
	fmt.Println("file name=", f("jack"))
	fmt.Println("file name=", f("jack.jpg"))
	fmt.Println("file name=", makeSuffix2(".jpg", "handsome"))
	fmt.Println("file name=", makeSuffix2(".jpg", "handsome.jpg"))
}

func main() {
	exec2()
}

defer:golang中的延时机制,常用于资源释放,以便于在使用资源时就定义延时释放,以免忘记关闭

package main

import "fmt"

func main() {
	//defer的命令延时执行,按先入后出顺序
	//defer中的变量值也保存了初始状态
	n := 1
	defer fmt.Println("defer1", n)
	defer fmt.Println("defer2", n)
	defer fmt.Println("defer3", n)
	n++
	fmt.Println("n=", n)
}

函数参数的传递方式

值传递:将值拷贝,数据越大效率越低; 基本数据类型int、float、bool、string、数组、结构体 引用传递:地址的拷贝,效率高;指针、切片、map、管道、接口等
如果希望函数内修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量

变量的作用域

函数内部声明/定义的变量,作用域仅限于函数内部 赋值语句不能在函数外执行,全局变量 Name := “jack” 会编译报错

package main

import (
	"fmt"
	"funcinit/utils"
)

var tmp = test()

func test() int {
	fmt.Println("test()")
	return 90
}

func init() {
	fmt.Println("init()...")

}

func main() {
	fmt.Printf("main()...tmp=%v\n", tmp)
	fmt.Printf("age=%v,name=%v", utils.Age, utils.Name)

}

package utils

import "fmt"

var Age int
var Name string

//Age和Name需要在main.go中使用
//但是需要初始化

//通过init函数完成初始化
func init() {
	fmt.Println("init包")
	Age = 100
	Name = "jack"
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值