go语言编程系列(四)

简介: go语言编程系列(四)

函数

Go语言函数式组织好的,可重复使用的,用于执行指定任务的代码块。Go语言中定义函数使用func关键字,具体格式如下:


func 函数名(参数)(返回值) {   函数体}

函数可以没有参数或接受多个参数

例如:


package basicimport "fmt"func Add(a, b int) int {   var ret = a + b   fmt.Printf("The sum of %d and %d is: %d\n", a, b, ret)   return ret}func Callback(y int, f func(int, int) int) {   f(y, 5) // this becomes Add(1, 5)}func DoCallback(y int) {   Callback(y, Add) // this becomes Add(1, 5)}

在本例中,add接受两个int类型的参数

注意:go和java不同,函数的返回类型,在函数名之后

当连续两个或者多个函数的已命名形参类型相同时,除最后一个类型以外,其他都可以省略。

在本例中


func Add(a int, b int) int {....}

其中的两个参数


a int, b int

被缩写为


a, b int

函数的定义:

函数构成代码执行的逻辑结构

除了main函数,返回值以及它们的类型被统称为函数签名


func function_name( [parameter list] ) [return_types] {   body(函数体)}

函数定义:

①、func:函数由func开始声明

②、function_name:函数名称,函数名和参数列表一起构成了函数签名

③、parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数,参数列表指定的是参数类型,顺序,及参数个数,参数是可选的,也就是说函数也可以不包含参数。

④、return_types:返回类型,函数返回列值,return_types是该列值的数据类型,有些功能不需要返回值,这种情况下return_types不是必须的。

⑤、body(函数体):函数定义的代码集合

形式参数列表描述了函数的参数名和参数类型

这些参数作为局部变量,其值由参数调用者提供,返回值列表描述了函数返回值的变量名以及类型

如果函数返回一个无名变量或者没有返回值,返回值列表的括号是可以省略的。

如果一个函数声明不包括返回值列表,那么函数体执行完毕,不会返回任何值。


// 这个函数计算两个int型输入数据的和,并返回int型的和func Add(a int, b int) int {  // Go需要使用return语句显式地返回值  return a + b}fmt.Println(Add(3,4)) //函数的调用

在Add函数中a和b是形参名 3和4是调用时的传入参数,函数返回了一个int类型的值

返回值也可以像形式参数一样被命名。

在这种情况下,每个返回值被声明成一个局部变量,并根据该返回值的类型,将其初始化为0.

如果一个函数在声明时,包含返回值列表,该函数必须以return语句结尾,除非函数明显无法运行到结尾处,例如函数在结尾处调用了panic异常或者函数中存在无限循环。

函数如何调用:

那么函数在使用的时候如何被调用呢?


package.Function(arg1, arg2, …, argn)

1、Function是package包里面的一个函数,括号里的是被调用函数的实参:这些值被传递给被调用函数的形参。

2、函数被调用的时候,这些实参将被复制然后传递给被调用函数。

3、函数一般是在其他函数里面被调用的,这个其它函数被称为调用函数。

4、函数能多次调用其他函数,这些被调用函数按顺序执行,理论上,函数调用其他函数的次数是无序的直到函数调用栈被耗尽。

函数的变长参数

在函数中有的时候可能也会遇到你要传递的参数的类型是多个(传递变长参数)如这样的函数


func patent(a,b,c ...int)

参数是采用...type的形式传递,这样的函数被称为变参函数

只有声明没有body的函数

你可能遇到没有声明函数体的函数声明,这表示该函数不是以go实现的

这样的声明定义了函数标识符


package mathfunc Sin(x float64) float //implemented in assembly language

返回多值的函数

函数可以返回任意数量的返回值

swap函数返回了两个字符串


//函数定义func Swap(x, y string) (string, string) {  return y, x}//函数调用func main() {  basic.BasicTypeDemo()  basic.BasicTypeDemo()  basic.DoCallback(1)  basic.Callback(1, basic.Add)  a, b := basic.Swap("hello", "world")  fmt.Println(a, b)}

命名返回值

Go的返回值可被命名,它们会被视作定义在函数顶部的变量。

返回值的名称应当具有一定的意义,它可以作为文档使用。

没有参数的return语句,返回已命名的返回值,也就是直接返回


func Split(sum int) (x, y int) {  x = sum * 4 / 9  y = sum - x  return}

函数的使用


x, y := basic.Split(40)fmt.Println(x, y)

直接返回语句应当仅用在上面这样的短函数中,在长的函数中他们会影响代码的可读性。

匿名返回值

函数签名中命名返回值变量,只指定返回值类型,由return指定返回值


// 匿名返回值func Split02(sum int) (int, int) {  var x = sum * 4 / 9  var y = sum - x  return x, y}

任何一个非命名返回值在return语句里面都要明确指出包含返回值的变量或是一个可计算的值。

建议:尽量使用命名返回值:会使代码更清晰,更简短,同时更加容易读懂。

将函数作为参数传递

在Go语言中,函数是一等公民,也就是说,函数可以像值一样传递和使用。因此,可以将函数作为参数传递给其他函数,实现更加灵活的编程方式:


//类型:func(int, int) intfunc Add(a, b int) int {  var ret = a + b  fmt.Printf("The sum of %d and %d is: %d\n", a, b, ret)  return ret}func Callback(y int, f func(int, int) int) {   f(y, 5) // this becomes Add(1, 5)}  func DoCallback(y int) {   Callback(y, Add) // this becomes Add(1, 5)}

调用方法:


basic.DoCallback(1)basic.Callback(1, basic.Add)

输出结果:


The sum of 1 and 5 is: 6The sum of 1 and 5 is: 6

内置函数:

Go语言拥有一些不需要进行导入操作就可以使用的内置函数

它们有时可以针对不同的类型进行操作:例如,len,cap和append,或必须用于系统级的操作,例如:panic,因而,它们需要直接获得编译器的支持

a534c1bbb9099e3d8e611bc64fdaf3d1.png

内置接口:


type error interface {  //只要实现了Error()函数,返回值为String的都实现了err接口  Error() String}

递归函数:

当一个函数在其函数体内调用自身,则称之为递归

递归是一种强有力的技术特别是在处理数据结构的过程中。


// 递归函数定义func Processing(n int) (res int) {     if n <= 1 {     res = 1  } else {     res = Processing(n-1) + Processing(n-2)  }     return}  //调用  result := 0  for i := 0; i <= 10; i++ {  result = basic.Processing(i)  fmt.Printf("processing(%d) is: %d\n", i, result)}

输出结果:


processing(0) is: 1processing(1) is: 1processing(2) is: 2processing(3) is: 3processing(4) is: 5processing(5) is: 8processing(6) is: 13processing(7) is: 21processing(8) is: 34processing(9) is: 55processing(10) is: 89

在使用递归函数时经常会遇到一个重要的问题就是栈溢出:一般会出现在大量的递归调用导致的程序栈内存分配耗尽。

这个问题可以通过一个名为懒惰求值的技术解决,在go语言中,我们可以使用管道channel和goroutine也会通过这个方案来优化斐波那契数列的生成问题。

这样许多问题都可以使用优雅的递归来解决,比如说著名的快速排序算法

相关文章
|
7天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
26 2
|
12天前
|
JavaScript Java Go
探索Go语言在微服务架构中的优势
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出。本文将深入探讨Go语言在构建微服务时的性能优势,包括其在内存管理、网络编程、并发模型以及工具链支持方面的特点。通过对比其他流行语言,我们将揭示Go语言如何成为微服务架构中的一股清流。
103 53
|
6天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
15 2
|
6天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
19 2
|
11天前
|
Ubuntu 编译器 Linux
go语言中SQLite3驱动安装
【11月更文挑战第2天】
34 7
|
11天前
|
关系型数据库 Go 网络安全
go语言中PostgreSQL驱动安装
【11月更文挑战第2天】
42 5
|
10天前
|
安全 Go
用 Zap 轻松搞定 Go 语言中的结构化日志
在现代应用程序开发中,日志记录至关重要。Go 语言中有许多日志库,而 Zap 因其高性能和灵活性脱颖而出。本文详细介绍如何在 Go 项目中使用 Zap 进行结构化日志记录,并展示如何定制日志输出,满足生产环境需求。通过基础示例、SugaredLogger 的便捷使用以及自定义日志配置,帮助你在实际开发中高效管理日志。
28 1
|
10天前
|
程序员 Go
go语言中的控制结构
【11月更文挑战第3天】
86 58
|
9天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
10天前
|
存储 编译器 Go
go语言中的变量、常量、数据类型
【11月更文挑战第3天】
27 9