函数基本语法

func 函数名(形参列表)(返回值列表){
执行语句
return 返回值列表
}//返回值可以没有可以有多个可以有一个

引入

为了解决两个程序员取得函数名同名的情况

原理

本质就是创建不同的文件夹

概念

go的每一个文件都属于一个包,即go是以包来管理文件和项目目录结构的

作用

区分相同名字的函数,变量等标识符

程序文件很多时,很好的管理项目

控制变量,函数等访问范围,即作用域,大写公有,小写私有

说明

package:包名

import:包的路径

使用注意事项

给一个文件打包,该包对应一个文件夹,文件的包名通常和文件所在的文件夹名一致,一般为小写字母

要用包,先引包

import(

"包名"

”包名“

)

import “包名”

package指令在第一行,然后是import

在import包时,路径从$GOPATH的src下开始,不用带src,编译器会自己从src下引入

函数首字母大写才可以让其他包文件访问本包文件

访问:包名.函数名

如果包名较长,支持给包取别名,但是,取别名后原来的包名不能再用

在import里:别名 包名

同一包下,不能有相同函数名,否则报错

语法规范

编译生成一个可执行文件,需要将这个包名声明称main,即package main,但如果写的是一个库,包名可以自己定义

go build go_code/...../main

不需要带src编译器会自动带上

编译需编译main所在的文件夹

项目的目录结构最好按照规范来写

函数调用

说明

基本数据类型一般存放在栈区,编译器存在逃逸分析

引用类型存放在堆区,编译器存在逃逸分析

另外还有一个代码区

调用时分配新的空间,和其他栈区分开,每个空间独立不会混淆,函数执行完毕后销毁该空间

return语句

可接受多个,不想要可用占位符_忽略

若返回值有多个加(返回值类型列表),一个则不用_

res1, res2 := getsunAndsub(1,2)//该函数两个返回值
_, res2 := getsunAndsub(1,2)//占位符_忽略

递归

总结

执行函数,创建一个新的受保护的独立空间(新函数栈)

函数局部变量独立,不会相互影响

递归向退出递归条件的逼近,否则无限递归

函数执行完毕或遇到return就会返回,谁调用返回睡,自身销毁

小细节

数组是值传递,函数内修改,不会影响原来的值

希望函数可以改变函数外变量可以用&

函数内以指针操作

效果上看类似于引用

​ funct test(n1 *int){...}

​ test(&n1)

不同于c++的引用

​ int fun(int &a,int &b){...}

​ fun(a,b);

go中函数不支持重载,会报函数重复定义的错误

go中函数也是一种数据类型,可以赋值给一个变量,则该变量就是函数类型变量,可以通过改变量来对函数进行调用

func test(n int ,m,int){...}
a :=tset
res := a(10,20)//等价于res := test(10,20)

函数既然是一种数据类型,因此可以作为形参,并且调用

res2 :=myFun(getSun,n1,n2)
func myFun( funcvar fun(int, int) int, num1 int, num2 int) int{
return funcvar(num1,num2)
}
### go

支持自定义数据类型,可化简定义

type 自定数据类型名  数据类型
type myIny int
type myFuncType func(int, int )int
这是可用myFunType代替形参 func(int,int)int

支持函数返回值命名

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

_表示忽略

go支持可变参数

//支持0到多个参数
func sun(args...int) sun int{...}
//支持1到多个参数
func sum(n int, args...int) sun int{...}
//args是切片,通过args[index]访问到各个值

func sum(n1,n2 float)float{...}//n1 type=float

给函数类型的变量赋值函数:形参个数一样,返回值个数一样才算同种类型的即一个形参对应于一种函数类型

type myFuncType  func(int,  int )int
不能把func sum(n1,n2,n3 int)int{...}赋值给myFuncType

类型要匹配

init函数

介绍

每一个源文件都可以有一个init函数,会在main前执行,被go运行框架调用

通常在init中完成初始化工作

注意事项和细节

全局变量在init前执行

若import有utils.go则执行顺序

1.utils.go中的变量定义

2.utils.go中的init

3.main.go中的全局变量定义

4.main.go中的init

5.main.main函数

匿名函数(是一种类型)

没有名字,若只希望用一次,可以考虑使用匿名函数,当然也可调用多次

	res := func( n1 int, n2 int) int {
return n1 +n2
}(10 ,20)
//这种方式为定义时调用,只能调用一次
res := func( n1 int, n2 int) int {
return n1 +n2
}
res2 := res(10 ,20)
//将函数付给一个变量,通过变量可多次调用匿名函数

全局匿名函数

将匿名函数付给一个全局变量,那吗可在程序中有效

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

闭包

就是一个函数和其相关的引用环境组合的一个整体

func AddUpper() func (int) int {
var n int = 10
return func (x int) int {
n = n+x
return n
}
}
//AddUpper是一个函数,返回类型为func(int) int
//n的值类似于一个静态变量
f := AddUpper()
fmt.println(f(1))//11
fmt.println(f(2))//13

上面匿名函数和函数外的形成了一个整体,构成闭包

函数和他引用到的变量构成了闭包

案例

判断文件后缀名是否为jpg,给文件加或不加

闭包完成

内函数引用到外函数的形参或定义的变量构成闭包

闭包可以保留上次引用的值,所以

优点:传入一次就可以反复使用

package main
import (
"fmt"
"strings"
)
func makeSuffix(suffix string) func (string) string { return func (name string) string {
//如果 name 没有指定后缀,则加上,否则就返回原来的名字
if !strings.HasSuffix(name, suffix) {
return name + suffix
} return name
}
} func makeSuffix2(suffix string, name string) string { //如果 name 没有指定后缀,则加上,否则就返回原来的名字
if !strings.HasSuffix(name, suffix) {
return name + suffix
} return name }
func main(){
//测试makeSuffix 的使用
//返回一个闭包
f2 := makeSuffix(".jpg") //如果使用闭包完成,好处是只需要传入一次后缀。
fmt.Println("文件名处理后=", f2("winter")) // winter.jgp
fmt.Println("文件名处理后=", f2("bird.jpg")) // bird.jpg fmt.Println("文件名处理后=", makeSuffix2("jpg", "winter")) // winter.jgp
fmt.Println("文件名处理后=", makeSuffix2("jpg", "bird.jpg")) // bird.jpg }

defer

why

函数中,程序员经常需要创建资源,为了在函数执行完毕后,及时释放资源,go的设计组提供了defer(延时机制)

执行到defer时将defer后面的语句压入到独立的栈中(defer栈)

当函数执行完毕后,再从defer栈中按先入后出的方式出栈

注意事项

defer入栈时,会将相关值进行拷贝一起放入栈,注意,此值不收其他表达式影响

其价值在于函数执行完毕后,及时释放函数创建的资源

创建资源

defer 释放资源,其他代码不用再担心在什么时候关闭资源

函数传参机制

值类型值拷贝,引用类型地址拷贝

一般来说地址拷贝效率高,因为数据小,而值拷贝,数据越大,效率越低

变量作用域

函数内部的作用域仅限于函数内

函数外部的定义变量叫作全局变量在整个包内有效,若首字母大写在整个程序有效

在一个代码块中定义,则只在代码块中有效

编译器会采用就近原则

name := "tom"//错误,因为等价于var Name string Name = "tom"

字符串常用的系统函数

统计字符串长度

len(str)

字符串遍历,可带中文

r :=[]rune(str)

字符串转整数

n,err := strconv.Atoi("12")

整数转字符串

str = strconv.Itoa(12345)

字符串转[]byte

var bytes = []byte("hello go")

[]byte转字符串

str = string([]byte{97,98,99})

10进制转2 8 16进制

str = strconv.FormatInt(132,2)

在母串中查子串

strings.Contains("seafood","food")

母串中统计子串

strings.Counts("seafood","food")

不区分大小写的比较

stringsEqualFold("abc",""ABC)

返回子串在字符串第一次出现的index若没有返回-1

strings.Index("NLT_abc","abc")

指定子串替换为另一个子串

strings.Replace("go go hello","go","go语言",n)//n可指定几个-1表示全部替换

按照特定的某个字符为标识符将一个字符串拆分成字符数组

strings.Split("hello,word,ok",",")

字符串大小写转换

strings.TOLower("Go")

strings.ToUpper("Go")

将字符串两边的空格去掉

strings.TrimSpace(" asassdf ")

将字符串两边指定字符去掉

strings.Trim("! hello!","!")//["!"],将“!”去掉

strings.TrimLeft()去左边

strings.TrimRight()去右边

判断是否已指定的字符串开头

strings.HasPrefix("ftp://192.168.10.1","ftp")

strings.HasSuffix()判断是否已字符串结束

时间和日期相关的函数

需先引入time包

time.Time获取时间

now := time.now()

now.year()

分秒以此类推,返回类型为字符串型可转换

格式化时间

法一:用Print或Sprintf

法二: 用time.Format()完成

注意格式

单位

Nanosecond纳秒

Microsecond微妙

Millisecond毫秒

在程序中获取指定单位的时间 100*time.Millisecond

结合sleep使用:time.Sleep(100*time.Millisecond)

time的UnixNano和Unix

时间戳

获取时间的单位为妙

单位为纳秒

Now.Unix() 从1970年1月1日到现在的时间差

可用来统计一个函数执行的时间。利用时间戳

内置函数

len用来求长度

new用来分配内存,主要分配值类型,返回的是指针返回值是一个地址的数值,地址又是一个数值,都是系统分配的

make用来分配地址主要用于引用类型

错误处理

希望错误出现后可以捕获到错误并进行处理保证程序执行,还可以不货到后给管理员一个提示(邮件或短信),而不是崩溃,所以引出错误处理机制

go追求优雅,所以不支持try..catch...finally处理方式为defer,panic,recover

抛出一个panic错误然后在defer中通过recover捕获这个异常,然后正常处理

defer+recover处理

defer fucn() {
err := recover()
if err != nil {
fmt.Println("err=",err)
}
}

recover内置函数可以捕获到异常

错误处理好处

程序不会轻易挂掉,加入警戒代码,让代码更健壮

自定义错误

使用errows.New和panic内置函数

errors.New("错误说明"),会返回一个error类型的值,表示一个错误

panic内置函数接受一个interface{}类型的值(也就是任和值了),可以接受error类型变量,输出错误信息,并退出程序

package main
import (
"fmt"
_ "time"
"errors"
) func test() {
//使用defer + recover 来捕获和处理异常
defer func() {
err := recover() // recover()内置函数,可以捕获到异常
if err != nil { // 说明捕获到错误
fmt.Println("err=", err)
//这里就可以将错误信息发送给管理员....
fmt.Println("发送邮件给admin@sohu.com~")
}
}()
num1 := 10
num2 := 0
res := num1 / num2
fmt.Println("res=", res)
} //函数去读取以配置文件init.conf的信息
//如果文件名传入不正确,我们就返回一个自定义的错误
func readConf(name string) (err error) {
if name == "config.ini" {
//读取...
return nil
} else {
//返回一个自定义错误
return errors.New("读取文件错误..")
}
} func test02() { err := readConf("config2.ini")
if err != nil {
//如果读取文件发送错误,就输出这个错误,并终止程序
panic(err)
}
fmt.Println("test02()继续执行....")
} func main() { //测试
// test()
// for {
// fmt.Println("main()下面的代码...")
// time.Sleep(time.Second)
// } //测试自定义错误的使用 test02()
fmt.Println("main()下面的代码...")
}

最新文章

  1. 使用国内镜像加速下载Android SDK
  2. spring mvc参数绑定
  3. Java正则获取邮箱
  4. 在 Xcode 6 中使用矢量图( iPhone 6 置配 UI)
  5. 2014 Multi-University Training Contest 4
  6. java中汉字自动转换成拼音
  7. sublime 配置g++
  8. [Unity3D]Unity3D游戏开发之自己主动寻路与Mecanim动画系统的结合
  9. rotate.js实现图片旋转 (chrome,IE,firefox都可以实现)
  10. Android 开发佳站3
  11. 用 Google 挖掘赚钱思路
  12. GCC 中的编译器堆栈保护技术
  13. iView -- TimePicker 自定义修改时间选择器选择时间面板样式
  14. 【Java基础】【11Eclipse使用&Object类型】
  15. There/Here be句型
  16. BZOJ5210 最大连通子块和 【树链剖分】【堆】【动态DP】
  17. print
  18. MySQL导出数据字典
  19. markdown上下左右,跳至行尾行首,重设快捷键
  20. BZOJ.3920.Yuuna的礼物(莫队 分块套分块 分段离散化)

热门文章

  1. javascript基础修炼(12)——手把手教你造一个简易的require.js
  2. Java并发总结
  3. js写个小时钟
  4. vue发送ajax请求
  5. Kafka与RabbitMQ对比
  6. 2019 DevOps 必备面试题——DevOps 理念篇
  7. IDEA中GitLab的使用
  8. Android获取实时连接热点的设备IP地址
  9. Linux iotop工具简介
  10. bay——linux6.5-PV-LV-VG扩容.txt