GO语言学习之函数,包和错误处理
1.基本介绍
为完成某一功能的程序指令(语句)的几何,成为函数
在go中,函数分为:自定义函数,系统函数
2.函数的语法
func 函数名(形参列表)(返回值列表){
函数体
return 返回值列表
}
1》形参列表:表示函数的输入
2》函数体:表示为了实现某一功能代码块
3》函数可以有返回值,也可以没有
3.快速入门
用函数写一个计算器:
package main
import "fmt"
func jiSuanQi(num1 int,num2 int,caoZuo byte)int {
var res int
switch caoZuo {
case '+':
res=num1+num2
case '-':
res=num1-num2
case '*':
res=num1*num2
case '/':
res=num1/num2
case '%':
res=num1+num2
default:
fmt.Println("操作符号有误")
}
return res
}
func main() {
a:=8
b:=10
var c byte='+'
res:=jiSuanQi(a,b,c)
fmt.Println("结果为:",res)
res=jiSuanQi(a,b,'+')
fmt.Println("结果为:",res)
}
4.包
1》在实际开发中,我们往往需要在不同的文件中,去调用其它文件的定义的函数,比如:main.go中去使用 fmt包中的函数(一直在使用)
2》现在有两个程序员共同开发一个GO项目,程序员a希望定义一个jiSusanQi,程序员b,也希望定义一个jiSuanQi
,难道让他们每个人都定义嘛,那我们的代码是不是浪费了
包的原理就是创建不同的文件夹,存放不同的程序
》go中的每一个文件都属于一个包,也就是说go是以包的形式来管理文件和项目目录结构的
5.包的三大作用
》区分相同名字的函数,变量等标识符
》当程序文件很多时,可以很好的管理项目
》控制函数,变量等访问范围,级作用域
6.包的相关说明
》打包的基本语法
package 包名
》导入包的基本语法
import “包的路径”
7.包使用的快速入门》》》(注意)
相互调用的函数,我们将func Cal定义到 util.go文件中,将util.go放到一个包中,当其他文件需要使用到util.go中的方法时,可以import该包,通过包名调用
x的csdn上传不了图片
util.go中代码:
package util
import "fmt"
//注意:如果cal函数能被外部调用,首字母必须大写,类似于Java中public的功能
func Cal(num1 int,num2 int,caoZuo byte)int {
var res int
switch caoZuo {
case '+':
res=num1+num2
case '-':
res=num1-num2
case '*':
res=num1*num2
case '/':
res=num1/num2
case '%':
res=num1+num2
default:
fmt.Println("操作符号有误")
}
return res
}
main.go文件中代码
package main
import (
"fmt"
"byteDemo01/util"
)
func main() {
a:=8
b:=10
var c byte='+'
res:=util.Cal(a,b,c)
fmt.Println("结果为:",res)
res=util.Cal(a,b,'+')
fmt.Println("结果为:",res)
}
8.包使用的注意事项和细节讨论
1》在给一个文件打包时,该包对应一个文件夹,比如 util的文件夹对应的包名util,该文件夹下的所有文件都属于该包,包名一般为小写
2》当一个文件要使用其他包函数或变量时,需要先引入对应的包
语法:1.import “包名”
语法:2.
import(
“包名”
“包名”
)
注意:package 指令在文件第一行,然后是import指令
在import包时,路径从$GOPATH的src下开始,不用带src,编译器会自动从src下开始引入
3》为了让其他包的文件,可以访问到本报的函数,则该函数名的首字母需要大写,类似其他语言的public,这样才能挎包访问。
4》在·访问其他包函数,变量时,其语法时包名.函数名,
5》如果包名较长,GO支持给包取别名,注意细节:取别名后,原来的包名就不能使用了
import (
"fmt"
util|"byteDemo01/util"//需要用util来访问变量和函数
)
6》在同一包下,不能有相同的函数名(也不能有相同的全局变量名),否则重复定义
7》如果你要编译成一个可执行程序文件,就需要将这个包声明为main.即package main.这个是一个语法规范,如果你是写一个库,包名可以自定义
9.函数的调用机制
1.什么是函数?
你饿了,在饿了么上叫一个武圣羊肉汤,饿了么外卖员给我们送到手上。
程序员调用方法:给方法必要的餐宿,方法返回结果的过程
2.函数的调用过程
介绍:为了让大家更好的理解函数调用过程,看两个案例,并画出示意图—:
package main
func test(i int){
println(i+1)
}
func main() {
i :=10
test(i)
println(i)
}
// 11
// 10
//为什么?画图分析堆栈
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YUEbXDTg-1575259853241)(C:\Users\xiaoweifeng\AppData\Roaming\Typora\typora-user-images\1575204427591.png)]
1》在调用一个函数时,会给该函数分配一个新的空间,编译器会通过自身的处理让这个新的空间和其他的栈的空间区分开来
2》在每个函数对应的栈中,数据空间是独立的,不会混淆
3》当一个函数调用完毕后,程序会销毁这个函数对应的栈空间
3.return语句
基本语法:
go函数支持返回多个值,Java等只能返回一个值
func 函数名(形参列表)(返回值类型列表){
语句。。。
return 返回值列表
}
1》如果返回多个值时,在接收时,希望忽略某个返回值,则使用_符号表示占位忽略
2》如果返回值只有一个,(返回值类型列表)可以不写()
案例:
package main
import "fmt"
func test(i int,j int)(int ,int){
he:=i+j
cha:=i-j
return he,cha
}
func main() {
he,cha:=test(100,99)
fmt.Printf("和为%v,差为%v",he,cha)
//如果希望忽略he则可以这样写
_,cha=test(100,66)
fmt.Printf("差为%v",cha)
}
10.函数的递归调用
1.基本介绍
一个函数在函数体里面调用了自身,我们称之为递归函数
2.代码示例1:
package main
import "fmt"
func digui(n int) {
if n>0{
n--
digui(n)
}
fmt.Printf("n为%v\n",n)
}
func main() {
digui(10)
}
代码示例2:
package main
import "fmt"
func digui(n int) {
if n>0{
n--
digui(n)
}else {
fmt.Printf("n为%v\n",n)
}
}
func main() {
digui(10)
}
根据两个案例结果来分析。
3.递归调用总结:
1》执行一个函数时,就创建一个新的受保护的独立空间(新函数栈)
2》函数的局部变量是独立的,不会相互影响
3》递归必须向退出递归的条件逼近,否则就没有出口,死鬼
4》当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当函数执行完毕或者返回时,该函数本身也会被系统销毁
4.递归小练习:
1》斐波那契数
1,1,2,3,5,8,13.。。
思路:
当n1||n2,返回1
当n>=2,返回前面两个数的和f(n-1)+f(n-2)
代码:
package main
import "fmt"
func f(n int)int{
if (n==1||n==2){
return 1
}else {
return f(n-2)+f(n-1)
}
}
func main() {
fmt.Println("res=",f(1))
fmt.Println("res=",f(2))
fmt.Println("res=",f(3))
fmt.Println("res=",f(4))
fmt.Println("res=",f(5))
fmt.Println("res=",f(6))
}
2》求函数值
已知f(1)=3;f(n)=2*f(n-1)+1;
使用递归的方式,求出 f(n)的值
package main
import "fmt"
func df(n int) int {
if n==1{
return 3
}else {
return 2*df(n-1)+1
}
}
func main() {
fmt.Println("res:",df(2))
fmt.Println("res:",df(3))
fmt.Println("res:",df(4))
}
3》猴子吃桃子
有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个,以后猴哥每天都吃一半,然后再多吃一个,当第十天想再吃(h还没吃),发现只有一个桃子了
思路:
第10天有一个
第九天=(第十天的数量+1)*2
规律,第n天的桃子=peach(n)=(peach(n+1)+1)*2
package main
import "fmt"
func tao(n int)int {
if(n>10||n<1){
fmt.Println("您输入天数不正确")
return 0
}
if n==10{
return 1
}else {
return (tao(n+1)+1)*2
}
}
func main() {
fmt.Println("第一天桃子数为:",tao(1))
}
11.函数使用细节和注意事项
1》函数的形参列表可以是多个,返回值列表也可以是多个
2》形参列表和返回值列表的数据类型可以是值类型和引用类型
3》函数的命名遵循标识符命名规范,首字母不能是数字,首字母大写该函数可以被本包文件和其他包文件使用,类似public,首字母小写,只能被本包文件调用,其他文件不能调用,类似于private
4》函数中的变量是局部的,函数外不生效
package main
func a(){
var n int=66
println(n)
}
func main() {
//a 中的只能在 a中用
a()
n=88
}
5》基本数据类型和数组默认都是值传递的,即进行值拷贝,在函数内修改,不会影响到原来的值
package main
import "fmt"
func xt(n int){
n=n+1
fmt.Println("n=",n)
}
func main() {
n:=10
xt(n)//n=11
fmt.Println(n)//10
}
6》如果希望函数内的变量能修改函数外的变量(指的是默认以值传递的方式的数据类型),可以传入变量的地址&,函数内以指针的方式操作变量,从效果上看类似引用(难点)化内存图
package main
import "fmt"
func ts(n *int) {
*n=*n+1
fmt.Println("n为",*n)
}
func main(){
n:=7
ts(&n)//8
fmt.Println(n)//8
}
7》GO函数不支持函数重载(java中函数重载是,同名函数,只要参数列表不一样都可以存在)
8》在go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量。通过该变量可以对函数调用
package main
import "fmt"
func add(a int,b int)int{
return a+b
}
func main(){
t:=add
fmt.Printf("t的类型为 %T,add函数的类型:%T\n",t,add)
//t的类型为 func(int, int) int,add函数的类型:func(int, int) int
x:=t(10,20)//等于 add(10,20)
fmt.Println(x)
}
9》函数既然是一种那个数据类型,因此在GO中,函数可以作为形参,并且被调用
package main
import "fmt"
func fun(a int,b int)int{
return a+b
}
func varFun(fun func(int,int)int ,num1 int,num2 int) int{
return fun(num1,num2)
}
func main(){
res:=varFun(fun,10,66)
fmt.Println("res=",res)
}
10》为了简化数据类型定义,GO支持自定义数据类型
基本语法:type 自定义数据类型名 数据类型 //相当于一个别名
案例 :type i int //i 就等价于int
案例:type t func(int,int)int// t<==>func(int ,int)int 函数型
package main
import "fmt"
func main(){
type aint int
var x aint=100
var y int
y=int(x)
fmt.Printf("x的类型为%T,a的值为 %v",x,x)
fmt.Printf("y的类型为%T,a的值为 %v",y,y)
}
package main
import "fmt"
type funct func(int,int)int //将函数型进行赋值
func fun(a int,b int)int{
return a+b
}
//将自定义函数型作为参数引用
func varFun(fun funct ,num1 int,num2 int) int{
return fun(num1,num2)
}
func main(){
res:=varFun(fun,10,66)
fmt.Println("res=",res)
}
11》支持对函数返回值命名
package main
import "fmt"
func jisuan(a int ,b int )(sub int,sum int){
sub=a-b
sum=a+b
return
}
func main() {
a,b:=jisuan(10,2)
fmt.Println("a=",a,"b=",b)
}
12》使用_标识符,忽略返回值,
a,_:=jisuan(10,2)
fmt.Println("a=",a)
13》go支持可变参数
//支持0到多个参数
func sum(args…int)sum int{
}
//支持1到多个参数
func sum(n1 int,agrs …int)sum int{
}
说明:
<1 args 是 slice切片,通过agrs[index],可以访问到各个值
<2.案例演示:编写一个函数sum,可以求出1到多个int的和
❤️.如果一个函数的形参列表中有可变参数,则可变参数需要放在形参列表最后
package main
import "fmt"
func getSum(args...int)int{
res:=0
for i:=0;i<len(args);i++{
res+=args[i]
}
return res
}
func main(){
res:=getSum(1)
fmt.Println("res:=",res)
res=getSum(1,100,0,4)
fmt.Println("res:=",res)
res=getSum(1,8,9,5)
fmt.Println("res:=",res)
}
12.函数练习:
1》编写一个交换值的函数
package main
import "fmt"
func swap(a int ,b int){
temp:=0
temp=b
b=a
a=temp
fmt.Println("a值为:",a,"b的值为:",b)
}
func main() {
a:=100
b:=99
swap(a,b)
}
参数
func sum(n1 int,agrs …int)sum int{
}
说明:
<1 args 是 slice切片,通过agrs[index],可以访问到各个值
<2.案例演示:编写一个函数sum,可以求出1到多个int的和
❤️.如果一个函数的形参列表中有可变参数,则可变参数需要放在形参列表最后
package main
import "fmt"
func getSum(args...int)int{
res:=0
for i:=0;i<len(args);i++{
res+=args[i]
}
return res
}
func main(){
res:=getSum(1)
fmt.Println("res:=",res)
res=getSum(1,100,0,4)
fmt.Println("res:=",res)
res=getSum(1,8,9,5)
fmt.Println("res:=",res)
}
12.函数练习:
1》编写一个交换值的函数
package main
import "fmt"
func swap(a int ,b int){
temp:=0
temp=b
b=a
a=temp
fmt.Println("a值为:",a,"b的值为:",b)
}
func main() {
a:=100
b:=99
swap(a,b)
}