GO开发[四]:golang函数
函数
1.声明语法:func 函数名 (参数列表) [(返回值列表)] {}
2.golang函数特点:
a. 不支持重载,一个包不能有两个名字一样的函数
b. 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量
c. 匿名函数
d. 多返回值
定义函数类型type:
package main
import "fmt"
type add_func func(int, int) int
func add(a, b int) int {
return a + b
}
func sub(a, b int) int {
return a - b
}
func operator(op add_func, a int, b int) int {
return op(a, b)
}
func main() {
c := add
fmt.Println(c)
sum := operator(c, 100, 200)
fmt.Println(sum)
var x add_func
x=sub
fmt.Println(x)
sub := operator(x, 100, 200)
fmt.Println(sub)
}
3.函数参数传递方式:
1). 值传递
2). 引用传递
注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。
引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。
注意2:map、slice、chan、指针、interface默认以引用的方式传递
package main
import "fmt"
func modify(a *int) {
*a = 100
}
func main() {
a := 8
fmt.Println(a)
modify(&a)
fmt.Println(a)
}
参数类型省略:
func f(i, j, k int, s, t string)
func f(i int, j int, k int, s string, t string)
4.命名返回值的名字:
package main
import "fmt"
func split(sum int) (x, y int) {
x = sum / 10
y = sum % 10
return
}
func main() {
fmt.Println(split(17))
}
_标识符,用来忽略返回值
5.可变参数:
func add(arg …int) int {
}//0个或多个参数
func add(a int, arg …int) int {
}//1个或多个参数
func add(a int, b int, arg …int) int {
}//2个或多个参数
注意:其中arg是一个slice,我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数
练习:写一个函数add,支持1个或多个int相加,并返回相加结果
练习:写一个函数concat,支持1个或多个string相拼接,并返回结果
defer
1.当函数返回时,执行defer语句。可以用来做资源清理
2.多个defer语句,按先进后出的方式执行,即最后一个defer语句将最先被执行
3.defer语句中的变量,在defer声明时就决定了。
在函数将要返回前执行:
package main
import "fmt"
func print() {
defer func() {
fmt.Println("defer")
}()
fmt.Println("hello")
}
func main() {
print()
}
多个defer语句:
package main
import "fmt"
func main() {
var i int =1
fmt.Println(i)
defer fmt.Println(i)
//不会立即执行,压到栈里面,函数执行结束后,再执行栈里的
defer fmt.Println("a")
i=10
fmt.Println(i)
}
用途:
1.关闭文件句柄
2.锁资源释放
3.数据库连接释放
内置函数
1.close:主要用来关闭channel
2.len:用来求长度,比如string、array、slice、map、channel
3.new:用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针
package main
import "fmt"
func main() {
var i int
fmt.Println(i)
j := new(int)
fmt.Println(j)
fmt.Println(*j)
*j = 100
fmt.Println(*j)
}
4.make:用来分配内存,主要用来分配引用类型,比如chan、map、slice
new和make的区别:
package main
import "fmt"
func test() {
s1 := new([]int)
fmt.Println(s1)
s2 := make([]int, 10)
fmt.Println(s2)
*s1 = make([]int, 5)
(*s1)[0] = 100
s2[0] = 100
fmt.Println(s1)
fmt.Println(s2)
return
}
func main() {
test()
}
5.append:用来追加元素到数组、slice中
package main
import "fmt"
func main() {
var a []int
a = append(a,10,20,30)
a = append(a,a...)
fmt.Println(a)
}
错误处理error
Go语言引入了一个关于错误处理的标准模式,即error接口,该接口的定义如下:
type error interface {
Error() string
}
1.初始化失败,退出
2.重试,比如if err !=nil,重试3次
3.异常上抛
package main
import "fmt"
func print() {
var p *int
fmt.Println(*p)
}
func main() {
defer func() {
err := recover()
fmt.Println(err)
}()
panic("不想执行下去了")
//print()//1.空指针引用错误
//var n int
//fmt.Println(10 / n) //2.除数为0
/*
var i=3
var slice [3]int
fmt.Println(slice[i])//3.下标越界
*/
}
EOF error
recover.go:
Go语言引入了两个内置函数panic()和recover()以报告和处理运行时错误和程序中的错误场景:
当在一个函数执行过程中调用panic()函数时,正常的函数执行流程将立即终止,但函数中之前使用defer关键字延迟执行的语句将正常展开执行,之后该函数将返回到调用函数,并导致逐层向上执行panic流程,直至所属的goroutine中所有正在执行的函数被终止。错误信息将被报告,包括在调用panic()函数时传入的参数,这个过程称为错误处理流程。
recover()函数用于终止错误处理流程。一般情况下, recover()应该在一个使用defer关键字的函数中执行以有效截取错误处理流程。如果没有在发生异常的goroutine中明确调用恢复过程(使用recover关键字) ,会导致该goroutine所属的进程打印异常信息后直接退出。
package main
import (
"fmt"
"time"
)
func test() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
b:=0
a := 1/b
fmt.Println(a)
return
}
func main() {
for {
test()
time.Sleep(time.Second)
}
}
panic.go
package main
import (
"fmt"
"time"
"errors"
)
func initConfig() (err error) {
return errors.New("init config failed")
}
err := initConfig()
if err != nil {
panic(err)
}
return
}
func main() {
for {
test()
time.Sleep(time.Second)
}
}
递归
一个函数调用自己,就叫做递归。
package main
import (
"fmt"
"time"
)
func recusive(n int) {
fmt.Println("hello golang", n)
time.Sleep(time.Second)
if n > 10 {
return
}
recusive(n + 1)
}
func main() {
recusive(0)
}
递归实现阶乘和斐波那契数列:
package main
import (
"fmt"
"time"
)
func factor(n int) int {
if n == 1 {
return 1
}
return factor(n-1) * n
}
func fab(n int) int {
if n <= 1 {
return 1
}
return fab(n-1) + fab(n-2)
}
func main() {
fmt.Println(factor(5))
for i := 0; i < 10; i++ {
fmt.Println(fab(i))
}
}
函数类型
package main
import "fmt"
func print1(){
fmt.Println("print1")
}
func print2() {
fmt.Println("print2")
}
func func1(n int) int {
return n+1
}
func main() {
//变量是个筐,装这个变量类型的数据
//函数也是个筐,容器,装的函数
var f func()
f = print1
f()
f=print2
f()
var flist [3]func(int) int
flist[0]=func1
m:=flist[0](10)
fmt.Println(m)
fmt.Println(flist[0](10))
}
加减乘除:
package main
import (
"fmt"
"os"
"strconv"
)
func add(m, n int) int {
return m + n
}
func sub(m, n int) int {
return m - n
}
func comp(m,n int) int {
return m * n
}
func div(m,n int) int {
return m/n
}
func main() {
funcmap := map[string]func(int, int) int{
"+": add,
"-": sub,
"*":comp,
"/":div,
}
m, _ := strconv.Atoi(os.Args[1])
n, _ := strconv.Atoi(os.Args[3])
f := funcmap[os.Args[2]]
if f != nil {
fmt.Println(f(m, n))
}
}
匿名函数
匿名函数是指不需要定义函数名的一种函数实现方式
在Go里面,函数可以像普通变量一样被传递或使用,这与C语言的回调函数比较类似。不同的是, Go语言支持随时在代码里定义匿名函数。
package main
import (
"fmt"
"strings"
)
func toupper(s string) string {
return strings.Map(func(r rune) rune {
return r - ('a' - 'A')
}, s)
}
func main() {
f := func(x,y int) int {
return x + y
}
fmt.Println(f(1,2))
f1:=func(x,y int) int {
return x + y
}(1,3)
fmt.Println(f1)
fmt.Println(toupper("hello"))
}
闭包
闭包:一个函数和与其相关的引用环境组合而成的实体
package main
import (
"fmt"
)
func addn(n int) func(int) int {
return func(m int) int {
return m+n
}
}
func main() {
f := addn(3)
fmt.Println(f(12))
}
生成器:
package main
import "fmt"
func iter(s []int) func() int {
var i = 0
return func() int {
if i >= len(s) {
return 0
}
n := s[i]
i += 1
return n
}
}
func main() {
f := iter([]int{1, 2, 3})
fmt.Println(f())
fmt.Println(f())
fmt.Println(f())
}
GO开发[四]:golang函数的更多相关文章
- Javascript模式(第四章函数)------读书笔记
一 背景 js函数的两个特点:1 函数是第一类对象(first-class object):2 函数可以提供作用域 1 函数是对象: 1 函数可以在运行时动态创建,还可以在程序执行过程中创建 2 可以 ...
- php中strstr、strrchr、substr、stristr四个函数用法区别
php中strstr.strrchr.substr.stristr四个函数用法区别: php中strstr strrchr substr stristr这四个字符串操作函数特别让人容易混淆,常用的是s ...
- C#的百度地图开发(四)前端显示与定位
原文:C#的百度地图开发(四)前端显示与定位 有了这些定位信息,那要如何在前端的页面上显示出来呢?这需要用到百度地图的JavaScript的API.下面是示例代码. 前端代码 <%@ Page ...
- python全栈开发 生成器 :生成器函数,推导式及生成器表达式
python 全栈开发 1.生成器函数 2.推导式 3.生成器表达式 一.生成器函数 1.生成器: 生成器的本质就是迭代器 (1)生成器的特点和迭代器一样.取值方式和迭代器一样(__next__(), ...
- golang函数学习笔记
golang函数特点: a.不支持重载,一个包不能有两个名字一样的函数 b.函数是一等公民,函数也是一种类型,一个函数可以赋值给变量 c.匿名函数 d.多返回值 例子1 func add(a, b ...
- electron/nodejs实现调用golang函数
https://www.jianshu.com/p/a3be0d206d4c 思路 golang 支持编译成c shared library, 也就是系统中常见的.so(windows下是dll)后缀 ...
- STC8H开发(四): FwLib_STC8 封装库的介绍和注意事项
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
- Oracle数据库中调用Java类开发存储过程、函数的方法
Oracle数据库中调用Java类开发存储过程.函数的方法 时间:2014年12月24日 浏览:5538次 oracle数据库的开发非常灵活,不仅支持最基本的SQL,而且还提供了独有的PL/SQL, ...
- iOS开发之----常用函数和常数
介绍一下Objective-c常用的函数,常数变量 算术函数 [算术函数] 函数名 说明 int rand() 随机数生成.(例)srand(time(nil)); //随机数初期化int val = ...
随机推荐
- spring boot使用profile来区分正式环境配置文件与测试环境配置文件
转载请在页首注明作者与出处 一:前言 经常在开发的时候,项目中的配置文件,在个人开发的时候有一套配置文件,在测试环境有一套配置文件,在正式环境有一套配置文件,这个时候如果配置文件复杂,需要改的东西就特 ...
- 搭建lnmp教程
LNMP指的是一个基于CentOS/Debian 上安装Nginx.PHP.MySQL.php.可以在独立主机上轻松的安装LNMP生产环境. 1 安装nginx 如果是一台新的服务器可直接安装(若以前 ...
- JPA的基本使用
前提: 创建一个springboot项目 创建一个名为springboottest的MySQL数据库 1 jar包准备 jpa的jar包 mysql驱动的jar包 druid数据库连接池的jar包 l ...
- su和sudo命令的区别
一. 使用 su 命令临时切换用户身份 参考 1.su 的适用条件和威力 su命令就是切换用户的工具,怎么理解呢?比如我们以普通用户beinan登录的,但要添加用户任务,执行useradd ,bein ...
- K:java中序列化的两种方式—Serializable或Externalizable
在java中,对一个对象进行序列化操作,其有如下两种方式: 第一种: 通过实现java.io.Serializable接口,该接口是一个标志接口,其没有任何抽象方法需要进行重写,实现了Serializ ...
- Web框架django[Form]组件
新手上路 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试牛刀 1.创建Form类 # 创 ...
- 如何用Python在豆瓣中获取自己喜欢的TOP N电影信息
一.什么是 Python Python (蟒蛇)是一门简单易学. 优雅健壮. 功能强大. 面向对象的解释型脚本语言.具有 20+ 年发展历史, 成熟稳定. 具有丰富和强大的类库支持日常应用. 1989 ...
- HTML5新特性:元素的classList属性与应用
在html5新增的classList之前, 操作元素的class用的是className这个属性,而如果要向jquery封装的hasClass, removeClass, addClass, togg ...
- 【读书笔记与思考】《python数据分析与挖掘实战》-张良均
[读书笔记与思考]<python数据分析与挖掘实战>-张良均 最近看一些机器学习相关书籍,主要是为了拓宽视野.在阅读这本书前最吸引我的地方是实战篇,我通读全书后给我印象最深的还是实战篇.基 ...
- msgpack库的神奇用法
一般来说,我们会把头部和实际消息分开定义,因为内部工作的worker之间发送消息有些额外的字段,这些字段不属于实际的消息.这时候我们会把worker消息中一个字段定义为interface{}或者obj ...