函数基本语法

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. Ubuntu安装Node和npm

    本文简单介绍在Ubuntu上安装最新版本的node和npm. 本次试验环境是Ubuntu 18.10. 安装nodejs root@ubuntu:~# cat /etc/issue Ubuntu 18 ...

  2. C# 模拟Windows键盘事件

    发送键盘消息 [DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true) ...

  3. Java操作数据库——使用JDBC连接数据库

    Java操作数据库——使用JDBC连接数据库 摘要:本文主要学习了如何使用JDBC连接数据库. 背景 数据持久化 数据持久化就是把数据保存到可掉电式存储设备中以供之后使用.大多数情况下,特别是企业级应 ...

  4. linux脚本判断当前的linux版本是6还是7

    #!/bin/sh version="release 7." release=$(cat /etc/redhat-release) echo $release result=$(e ...

  5. vue-cli 引用elementUI打包后文件过大

    解决方案:使用externals引用第三方资源,防止element资源被打包到自己项目中,(总共修改3个页面index.html.webpack.base.conf.js.main.js) 1.修改i ...

  6. 利用Azure虚拟机安装Dynamics 365 Customer Engagement之九:新建组织

    我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...

  7. MySQL复习值代码知识点(1)

    MySQL复习值代码知识点 一. 创建数据库 create database 数据库名: 二. 删除数据库 drop database 数据库名: 三. 选择相应的数据库 use 数据库名: 四. 创 ...

  8. 模块二之序列化模块以及collections模块

    模块二之序列化模块以及collections模块 一.序列化模块 json模块 ''' 序列化:将python或其他语言的数据类型转换成字符串类型 json模块: 是一个序列化模块. json: 是一 ...

  9. python--django for 循环中,获取序号

    功能需求:在前端页面中,for循环id会构不成连续的顺序号,所以要找到一种伪列的方式来根据数据量定义序号 因此就用到了在前端页面中的一个字段 forloop.counter,完美解决 1 <tb ...

  10. bay——Oracle RAC集群体系结构.docx

    Oracle RAC集群体系结构 ————bayaim  2018年10月22日13:33 https://blog.51cto.com/ixdba/862207  一. Oracle集群体系结构 O ...