函数基本语法

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()下面的代码...")
}

go-函数和错误处理的更多相关文章

  1. jquery ajax 总是还未等到success回调就刷掉了,就进入了onError函数的错误案例分析

    jquery ajax 总是还未等到success回调就刷掉了,就进入了onError函数的错误案例分析: 同样的请求同时请求了2次,然后第二次的请求把第一次的给刷掉了! (比如:<div on ...

  2. 【PHP代码审计】 那些年我们一起挖掘SQL注入 - 6.全局防护Bypass之一些函数的错误使用

    0x01 背景 PHP程序员在开发过程中难免会使用一些字符替换函数(str_replace).反转义函数(stripslashes),但这些函数使用位置不当就会绕过全局的防护造成SQL注入漏洞. 0x ...

  3. Linux kernel ‘lbs_debugfs_write’函数数字错误漏洞

    漏洞名称: Linux kernel ‘lbs_debugfs_write’函数数字错误漏洞 CNNVD编号: CNNVD-201311-421 发布时间: 2013-11-29 更新时间: 2013 ...

  4. Linux kernel get_prng_bytes函数数字错误漏洞

    漏洞名称: Linux kernel get_prng_bytes函数数字错误漏洞 CNNVD编号: CNNVD-201310-142 发布时间: 2013-10-11 更新时间: 2013-10-1 ...

  5. 类模板语法知识体系梳理(包含大量常犯错误demo,尤其滥用友元函数的错误)

    demo 1 #include <iostream> #include <cstdio> using namespace std; //template <typenam ...

  6. OPENSSL问题,使用fsockopen()函数提示错误

    环境配置 系统环境 CentOS7.2WDCP v3.2.2 lanmp PHP 多版本 指定使用5.6 OpenSSL 1.0.2h  3 May 2016 php.ini相关设置allow_url ...

  7. linux下使用gcc/g++编译代码时gets函数有错误

    今天在linux中使用个g++编译一个名为myfirst.cpp的代码的时候,出现如下错误 myfirst.cpp: In function ‘int main()’:myfirst.cpp:11:2 ...

  8. C++成员函数指针错误用法警示(成员函数指针与高性能的C++委托,三篇),附好多评论

    今天做一个成绩管理系统的并发引擎,用Qt做的,仿照QtConcurrent搞了个模板基类.这里为了隐藏细节,隔离变化,把并发的东西全部包含在模板基类中.子类只需注册需要并发执行的入口函数即可在单独线程 ...

  9. C++ socket bind() 函数绑定错误

    VS2015编译错误: errorCxxxx: 'initializing' : cannot convert from 'std::_Bind<false,void,SOCKET&,s ...

  10. sprintf()函数可能发生的错误

    接收到如下数据: GET http://app.tdvpn.com/heartbeat?mac=898607B81017AT+CIPSTATUS? &status=/ HTTP/1.1 Hos ...

随机推荐

  1. ansible执行带有环境变量的脚本不生效

    1背景 jenkins发布时,使用ansible执行远程主机上的启动tomcat脚本发现不生效,启动tomcat的脚本中有环境变量. ansible主机为:172.16.35.8 tomcat服务器为 ...

  2. 最强Linux shell工具Oh My Zsh 指南

    引言 笔者已经使用zsh一年多了,发现这个东东的功能太强大了.接下来,给大家推荐一下. 以下是oh-my-zsh部分功能 命令验证 在所有正在运行的shell中共享命令历史记录 拼写纠正 主题提示(A ...

  3. 使用DEV C++调试代码

    0.序言 本片博客旨在记录通过DEV C++工具调试C/C++代码,在这之前需要对以下知识了解或掌握. C/C++代码的完整编译过程,可参考文章 GCC,gcc,g++,gdb的区别和联系,可参考文章 ...

  4. Mysql高手系列,连载中

    Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 第1篇:mysql基础知识 第2篇:详解mys ...

  5. Slickflow.NET 开源工作流引擎快速入门之二: 简单并行分支流程代码编写示例

    前言:对于急切想了解引擎功能的开发人员,在下载版本后,就想尝试编写代码,完成一个流程的开发和测试.本文试图从一个最简单的并行分支流程来示例说明,如何快速了解引擎代码的编写. 版本:.NET Core2 ...

  6. 关于mybtis 使用过程中发生There is no getter for property named 'id' in class 'java.lang.String' 错误

    今天在修改一个关于mybtis语句时,偶然发现的一个错误  There is no getter for property named 'id' in class 'java.lang.String' ...

  7. 解决Mac下java多版本共存问题

    一.系统环境 macOS High Sierra(版本:10.13.6) MacBook Air (13-inch, Early 2015) 二.解决步骤 1. 新建.bash_profile文件 $ ...

  8. WPF--事件列表

    事件 描述 Annotation.AnchorChanged 新增.移除或修改 Anchor 元素时发生. Annotation.AuthorChanged 新增.移除或修改 Author 元素时发生 ...

  9. Oracle 11gR2 RAC网络配置,更改public ip、vip和scanip

    Oracle 11gR2 RAC网络配置,更改public ip.vip和scanip 转载黑裤子 发布于2018-10-30 01:08:02 阅读数 2898  收藏 展开 转载. https:/ ...

  10. Java使用FeignClient发送HTTP 请求

    使用FeignClient发送HTTP请求1.添加依赖<!-- spring cloud jar--><dependency> <groupId>org.sprin ...