函数
完成某一功能程序指令集合
定义语法
func 函数名(形参列表)(返回值列表){
执行语句
return 返回值列表
}
示例代码
func main () {
fmt.Println("结果==",cal(1.1,3.0,'+'))//4.1
}
func cal ( n1 float64, n2 float64,opreator byte)( float64){
var res float64
switch opreator {
case '+':
res = n1 + n2
case '-':
res = n1 - n2
case '*':
res = n1 * n2
case '/':
res = n1 / n2
default:
fmt.Println("操作符不正确")
}
return res
}
多值返回代码示例
func main () {
//fmt.Println("结果==",util.Cal(1.1,3.0,'+'))//4.1
res1,res2 := getSumAndSub(1,2)
res3,_ := getSumAndSub(1,2)
fmt.Println(res1,res2,res3)
}
func getSumAndSub(n1 int ,n2 int)(int,int){
sum := n1 + n2
sub := n1 - n2
return sum,sub
}
//声明返回值名称
func getSumAndSub2(n1 int ,n2 int)(sum int,sub int){
sum = n1 + n2
sub = n1 - n2
return
}
//可变参数
func getSum(n1 int,args... int) int {
var res int = n1
for i :=0 ; i<len(args); i++{
res += args[i]
}
return res
}
注意点
- 函数传递中,基本数据类型和数组默认都是值传递,即进行值拷贝,在函数内修改不影响原来的值,如果希望函数中值的更改影响函数外的值,可以传入地址 &num,函数内通过指针的方式操作变量
- Go不支持函数重载
- Go中函数也是一种类型可以赋值给变量,通过变量可以调用函数
- 函数可以作为形参传入函数
- 支持 对函数的返回值命名,命名后 return 后不用 追加 值返回。自动返回声明的返回值变量
- Go函数支持可变参数
包
用来区分同名的函数变量,更好的管理代码文件,控制 函数变量等的作用域
go中每个文件夹就是一个包
注意点
- 给一个文件打包时,该包对应一个文件夹,比如 示例中的package utils 和 package main,通常和文件夹一致一般为小写字母
- 当一个文件要使用其他包的函数或变量时,需要先引入对应的路径,如示例中 import go01/utils.引入包时,Go编译器自动在从GOPATH下的src开始查找路径并引入内容
- 包中的方法 变量 如果要被其他包引用到,必须首字母大写
- 调用其他包内容时 采用 包名.函数名的方式
- 如果包名很长 可以 import 时 起别名 如:import util “go01/utils” ,取包名后原来的包名就不能用了
- 同一包下,不能有相同的函数名或变量名,否则会提示重复定义
- 如果要编译成一个可执行程序文件,就需要把包声明为main,这个是语法规范,如果是编译成一个库,包名可以自定义
代码示例
go01/main下 main.go
package main
import (
"fmt"
util "go01/utils"
)
func main () {
fmt.Println("结果==",util.Cal(1.1,3.0,'+'))//4.1
}
go01/utils下 util.go
package utils
import (
"fmt"
)
func Cal ( n1 float64, n2 float64,opreator byte)( float64){
var res float64
switch opreator {
case '+':
res = n1 + n2
case '-':
res = n1 - n2
case '*':
res = n1 * n2
case '/':
res = n1 / n2
default:
fmt.Println("操作符不正确")
}
return res
}
init函数
每个文件都可以包含一个init函数,用于执行前的初始化工作,在函数在main函数执行前,会被Go运行框架调用。
注意点
- 如果一个文件同时包含全局变量定义,init函数和main函数 则执行顺序为:全局变量定义->init函数->main函数
- 如果main.go 调用了 util.go 二者都包含 init 方法和全局变量定义,那么执行顺序为:uitl变量定义->util init ->main 变量定义->main init 方法-> main main 方法
示例
func init(){
fmt.Println(" main init被执行...")
}
匿名函数
匿名函数就是没有名字的函数,如果一个函数只使用一次,可以考虑使用匿名函数,匿名函数也可以被多次调用
示例程序
func test1(){
//定义好函数后直接调用
res1 := func(n1 int,n2 int) int {
return n1 + n2
}(1,2)
fmt.Println(res1)
//将匿名函数赋值给 变量 然后通过变量调用,
//如果将函数赋值给 全局变量那么 函数可以全局调用
a := func(n1 int,n2 int) int {
return n1 + n2
}
fmt.Println(a(1,2))
}
闭包
闭包就是一个函数和它相关的引用环境组合成的一个整体。
测试代码
func test2(){
f1 := AddUpper(5);
fmt.Println(f1(1))
fmt.Println(f1(2))
}
// 定义一个函数 AddUpper 传入一个初始值 ,返回一个函数
// 函数调用时在 初始值基础上增加固定值
func AddUpper(n1 int) func(int) int{
var n int = n1
return func (x int) int{
n = n + x
return n
}
}
函数的defer
函数中程序员常需要创建资源(数据库连接、锁等),函数执行完毕后必须释放相应的资源,Go提供了defer 延迟机制来实现。更加方便
注意点
- 当go执行到refer时,不会立即执行defer后的语句,而是将defer后的语句压如到一个栈中,然后执行下一个语句
- 函数执行完毕后再从defer栈中,依次取出语句执行。
- defer将语句放入栈中时,也会将相关的值复制到栈中。方法中值类型变量的改变不会影响栈中的值
示例代码
func test3(n1 int,n2 int ) int {
defer fmt.Println("ok1 n1=",n1)//10
defer fmt.Println("ok2 n2=",n2)//20
n1++
n2++
res := n1 + n2
fmt.Println("res =",res)//32
return res
}
变量作用域
- 函数内部或语句块中定义的变量 作用域是本语句块
- 函数外声明的变量时全局变量,作用域是真个包,如果首字母大写则作用域是整个程序
常用函数
字符串常用函数
func test02(){
var str = "hahaz中文1243";
fmt.Println("字符串长度",len(str))
//字符串遍历 同时处理有中文的问题
r := []rune(str)
for i :=0;i<len(r);i++{
fmt.Printf("字符=%c",r[i])
fmt.Println("")
}
//字符串 转整型
n,err := strconv.Atoi("12")
fmt.Println("转整型:",n,err)
//整数转字符串
n2 := strconv.Itoa(12)
fmt.Println("转字符串:",n2)
//字符串 转 byte数组
var tytes = []byte(str)
fmt.Println("转字[]byte:",tytes)
// byte数组 转 字符串
var str2 = string(tytes)
fmt.Println("[]byte转字符串:",str2)
//10进制转 2、8、16进制
str2 = strconv.FormatInt(16,2)
fmt.Println("2进制:",str2)
str2 = strconv.FormatInt(16,8)
fmt.Println("8进制:",str2)
str2 = strconv.FormatInt(16,16)
fmt.Println("16进制:",str2)
//字符串包含
fmt.Println("是否包含:",strings.Contains("seafood","foo"))
fmt.Println("包含子字符串数量:",strings.Count("seafood","foo"))
fmt.Println("是否相同:",strings.EqualFold("Foo","foo"))
fmt.Println("子字符串第一次出现位置:",strings.Index("seafood","foo"))
fmt.Println("转大写:",strings.ToLower("sSEafood"))
fmt.Println("转小写:",strings.ToUpper("seafood"))
fmt.Println("去除两端空格:",strings.TrimSpace(" seafood "))
fmt.Println("去除两边空格和指定字符:",strings.Trim("sssesafoodsss","s"))
fmt.Println("去除左边空格和指定字符:",strings.TrimLeft("sssseafoodsss","s"))
fmt.Println("去除右边空格和指定字符:",strings.TrimRight("sssseafoodsss","s"))
fmt.Println("子字符串最后出现的位置:",strings.LastIndex("se123afood123","123"))
fmt.Println("替换字符串:",strings.Replace("se123afood123","123","1~3",-1))
fmt.Println("判断字符串开头:",strings.HasPrefix("http://123.com","http"))
fmt.Println("判断字符串结尾",strings.HasSuffix("http://123.com","com"))
fmt.Println("字符串拆分========")
strArr := strings.Split("zhagnsna,lisi",",")
for i:=0;i<len(strArr);i++{
fmt.Println(strArr[i])
}
}
时间和日期函数
func test03(){
now := time.Now()
fmt.Printf("当前时间 :%v,type: %T",now,now)
fmt.Println()
fmt.Println("当前时间信息:",now.Year(),now.Month(),now.Day(),
now.Hour(),now.Minute(),now.Second())
//Printf格式化时间
fmt.Printf("当前时间 :%d年%d月%d日%d时%d分%d秒",
now.Year(),now.Month(),now.Day(),now.Hour(),
now.Minute(),now.Second())
fmt.Println()
//time.Format 格式化日期 格式中的数字不能变 2006-01-02 15:04:05
fmt.Println("当前时间:"+now.Format("2006-01-02 15:04:05"))
//每100毫秒打印一个数字
for i:=0;i<10;i++{
fmt.Println(i)
time.Sleep(time.Millisecond * 100)
}
//h获取 从 1970年1月1日到指定时间 经过的时间 单位分别为秒和纳秒
fmt.Printf("unix时间戳:%v unixnano时间戳:%v \n",now.Unix(),now.UnixNano())
fmt.Println()
fmt.Println()
}
内置函数
Golang 为了方便编程提供了一些函数,可以直接使用,我们称之为内置函数,
- len:用来求长度 比如:string,array,slice,map,chnnel
- new:用来分配内存,主要用来分配值类型,如:int float32 ,struc 返回的是指针
- make:用来分配内存,主要用来为引用类型分配,比如 channel map slice
func test04(){
fmt.Println(len("123"))
num := new(int) // *int 类型
*num = 100
fmt.Printf("num 类型 %T,num 的值 %v,num 地址 %v %v \n",
num,*num,&num,*num)
}
错误处理
默认情况下发生错误后,程序会退出,我们可以在发生错误后进行捕获和处理,设置给管理员一个提示(邮件\短信)
- Golang追求优雅简介,所以不支持 传统的try catch finally 语句
- 通过defer panic recover ,程序跑出一个 panic异常,在defer中通过recover捕获这个异常并进行处理
- Golang支持自定义错误,
func test05(){
defer func(){
err := recover()
if err != nil{
fmt.Println("err=",err)
}
}()
num1 :=10
num2 :=0
res :=num1/num2
fmt.Println("res=",res)
}
//抛出自定义异常
func test06(){
defer func(){
//处理异常
err := recover()
if err != nil{
fmt.Println("test 06 err=",err)
}
}()
err :=errTest("hei")
if err != nil {
panic(err)//抛出异常
}
fmt.Println("抛出异常后还能执行吗")
}
func errTest( name string)(err error){
defer func(){
err := recover()
if err != nil{
fmt.Println("error Test err=",err)
}
}()
if name == "zhangsan"{
return nil
}else{
return errors.New("参数不合法")
}
}