函数

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函数的更多相关文章

  1. Javascript模式(第四章函数)------读书笔记

    一 背景 js函数的两个特点:1 函数是第一类对象(first-class object):2 函数可以提供作用域 1 函数是对象: 1 函数可以在运行时动态创建,还可以在程序执行过程中创建 2 可以 ...

  2. php中strstr、strrchr、substr、stristr四个函数用法区别

    php中strstr.strrchr.substr.stristr四个函数用法区别: php中strstr strrchr substr stristr这四个字符串操作函数特别让人容易混淆,常用的是s ...

  3. C#的百度地图开发(四)前端显示与定位

    原文:C#的百度地图开发(四)前端显示与定位 有了这些定位信息,那要如何在前端的页面上显示出来呢?这需要用到百度地图的JavaScript的API.下面是示例代码. 前端代码 <%@ Page  ...

  4. python全栈开发 生成器 :生成器函数,推导式及生成器表达式

    python 全栈开发 1.生成器函数 2.推导式 3.生成器表达式 一.生成器函数 1.生成器: 生成器的本质就是迭代器 (1)生成器的特点和迭代器一样.取值方式和迭代器一样(__next__(), ...

  5. golang函数学习笔记

    golang函数特点: a.不支持重载,一个包不能有两个名字一样的函数 b.函数是一等公民,函数也是一种类型,一个函数可以赋值给变量 c.匿名函数 d.多返回值   例子1 func add(a, b ...

  6. electron/nodejs实现调用golang函数

    https://www.jianshu.com/p/a3be0d206d4c 思路 golang 支持编译成c shared library, 也就是系统中常见的.so(windows下是dll)后缀 ...

  7. STC8H开发(四): FwLib_STC8 封装库的介绍和注意事项

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  8. Oracle数据库中调用Java类开发存储过程、函数的方法

    Oracle数据库中调用Java类开发存储过程.函数的方法 时间:2014年12月24日  浏览:5538次 oracle数据库的开发非常灵活,不仅支持最基本的SQL,而且还提供了独有的PL/SQL, ...

  9. iOS开发之----常用函数和常数

    介绍一下Objective-c常用的函数,常数变量 算术函数 [算术函数] 函数名 说明 int rand() 随机数生成.(例)srand(time(nil)); //随机数初期化int val = ...

随机推荐

  1. spring boot使用profile来区分正式环境配置文件与测试环境配置文件

    转载请在页首注明作者与出处 一:前言 经常在开发的时候,项目中的配置文件,在个人开发的时候有一套配置文件,在测试环境有一套配置文件,在正式环境有一套配置文件,这个时候如果配置文件复杂,需要改的东西就特 ...

  2. 搭建lnmp教程

    LNMP指的是一个基于CentOS/Debian 上安装Nginx.PHP.MySQL.php.可以在独立主机上轻松的安装LNMP生产环境. 1 安装nginx 如果是一台新的服务器可直接安装(若以前 ...

  3. JPA的基本使用

    前提: 创建一个springboot项目 创建一个名为springboottest的MySQL数据库 1 jar包准备 jpa的jar包 mysql驱动的jar包 druid数据库连接池的jar包 l ...

  4. su和sudo命令的区别

    一. 使用 su 命令临时切换用户身份 参考 1.su 的适用条件和威力 su命令就是切换用户的工具,怎么理解呢?比如我们以普通用户beinan登录的,但要添加用户任务,执行useradd ,bein ...

  5. K:java中序列化的两种方式—Serializable或Externalizable

    在java中,对一个对象进行序列化操作,其有如下两种方式: 第一种: 通过实现java.io.Serializable接口,该接口是一个标志接口,其没有任何抽象方法需要进行重写,实现了Serializ ...

  6. Web框架django[Form]组件

    新手上路 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试牛刀 1.创建Form类 # 创 ...

  7. 如何用Python在豆瓣中获取自己喜欢的TOP N电影信息

    一.什么是 Python Python (蟒蛇)是一门简单易学. 优雅健壮. 功能强大. 面向对象的解释型脚本语言.具有 20+ 年发展历史, 成熟稳定. 具有丰富和强大的类库支持日常应用. 1989 ...

  8. HTML5新特性:元素的classList属性与应用

    在html5新增的classList之前, 操作元素的class用的是className这个属性,而如果要向jquery封装的hasClass, removeClass, addClass, togg ...

  9. 【读书笔记与思考】《python数据分析与挖掘实战》-张良均

    [读书笔记与思考]<python数据分析与挖掘实战>-张良均 最近看一些机器学习相关书籍,主要是为了拓宽视野.在阅读这本书前最吸引我的地方是实战篇,我通读全书后给我印象最深的还是实战篇.基 ...

  10. msgpack库的神奇用法

    一般来说,我们会把头部和实际消息分开定义,因为内部工作的worker之间发送消息有些额外的字段,这些字段不属于实际的消息.这时候我们会把worker消息中一个字段定义为interface{}或者obj ...