Contents
4.1. 声明函数¶
4.1.1. 1.普通函数的声明形式¶
Go语言的函数声明以func标识,后面紧接着函数名、参数列表、返回参数列表及函数体, 具体形式如下:
func 函数名(参数列表)(返回参数列表){
函数体
}
· 函数名:由字母、数字、下划线组成。其中,函数名的第一个字母不能为数字。在同一个包内,函数名称不能重名。
· 参数列表: 一个参数由参数变量和参数类型组成。其中参数列表中的变量作为函数的局部变量而存在。
· 返回参数列表:可以是返回值类型列表,也可以是类似参数列表中变量名和类型名的组合。函数在声明有返回值时,必须在函数体中使用return语句提供返回值列表。
· 函数体: 能够被重复调用的代码片段
· 函数名首字母大写可以被其他包使用
4.1.2. 2.参数类型的简写¶
在参数列表中,如有多个参数变量,则以逗号分割;如果相邻变量是同类型,则可以将类型省略。 例如:
package main
import "fmt"
func func1(a, b int) int{
return a + b
}
func main() {
sum_num := func1(2,3)
fmt.Println(sum_num) //5
}
package main
import "fmt"
func functionA(a int, b int) {
fmt.Println(a + b)
}
func functionB(a, b int) {
fmt.Println(a * b)
}
func functionC(a bool) {
fmt.Println(!a)
}
func functionD(s string, d int) {
for i := 0; i <= d; i++ {
fmt.Println(s)
}
fmt.Println()
}
func main() {
functionA(10,20)
functionB(1,10)
functionC(false)
functionD("hello go",3)
}
4.1.3. 3.函数的作用域¶
package main
import "fmt"
// 包级别的作用域,全包生效
var float_num float64
func printNedd(width float64, height float64) float64 {
area := width * height
return area/float_num
}
func main() {
// 作用域变量进行赋值
float_num = 10.0
result :=printNedd(200,10)
fmt.Println(result)
}
4.1.4. 4.函数的返回值¶
Go 语言支持多返回值,多返回值方便地获得函数执行后的多个返回参数,Go语言经常使用多返回值中的最后一个返回参数 返回函数执行中可能发生的错误。示例代码如下:
conn,err := connectToNetwork()
这段代码中,connectToNetwork返回两个参数,conn表示连接对象,err返回错误。
Go语言既支持安全指针,也支持多返回值,因此在使用函数进行逻辑编写时更为方便。
4.1 同一种类型返回值¶
package main
import "fmt"
/*
纯类型的返回值对于代码可读性不是很友好,特别是在同类型的返回值出现时,无法区分每个返回参数的意义
*/
func typeTwoValues() (int, int) {
return 1, 2
}
func main() {
a, b := typeTwoValues()
fmt.Println(a, b) // 1 2
}
4.2 带有变量名的返回值¶
func namedRetValues() (a, b int) {
a = 1
return a, 2
}
注意: 同一种类型返回值和命名返回值两种形式只能二选一,混用时将会发生编译错误,例如下面的代码:
func namedRetValuse() (a,b,int,int)
4.3 调用函数¶
Go语言中函数调用格式如下:
返回值变量列表 = 函数名(参数列表)
· 函数名: 需要调用的函数名
· 参数列表: 参数变量以逗号分隔,尾部无需以逗号结尾
· 返回值变量列表: 多个返回值使用逗号分隔
例如,加法函数调用样式如下:
result := add(1,1)
一个将秒解析为时间的多返回值函数
package main
import "fmt"
const (
//分钟
SecondsPermiute = 60
//小时
SecondSPerHour = SecondsPermiute * 60
//天
SecondSPerDay = SecondSPerHour * 24
)
func resolveTime(seconds int) (day int, hour int, minute int) {
day = seconds / SecondSPerDay
hour = seconds / SecondSPerHour
minute = seconds / SecondsPermiute
return
}
func main() {
// 打印所有返回值
fmt.Println(resolveTime(1000)) //0 0 16
// 打印小时和分钟
_, hour, minue := resolveTime(18000)
fmt.Println(hour, minue) // 5 300
// 只获取天数
day,_,_ := resolveTime(90000)
fmt.Println(day) //1
}
4.4 函数变量-把函数作为值保存到变量中¶
package main
import "fmt"
func fire() {
fmt.Println("fire")
}
func main() {
//var f func()
//var f = fire // 将函数fire的值赋值给f
f := fire
f() // 调用函数
}
4.5 函数参数¶
package main
import "fmt"
/*//值传递
func swap(x,y int) int {
//TODO1
}*/
// 引用传递
func swap(x, y *int) {
var temp int
temp = *x // 保存x的值
*x = *y // 将y的值赋值给x
*y = temp //将temp的值赋值给y
}
func main() {
var x, y int = 5, 6
swap(&x, &y)
fmt.Println(x,y)
}
4.6 函数返回值¶
package main
func add(a, b int) (c int) {
c = a + b
return c
}
func calc(a, b int) (sum int, avg int) {
sum = a + b
avg = (a + b) / 2
return sum, avg
}
func main() {
println(add(1, 10))
a1, a2 := calc(10, 20)
println(a1, a2)
}
a4,_ :=calc(20,30) //使用_忽略掉不用的返回值
println(a4)
4.7 多返回值可直接作为其他函数调用实参¶
package main
func test() (x, y int) {
return 1, 2
}
func add(x, y int) int {
return x + y
}
func calc(s ...int) int {
var n int
for _, i2 := range s {
n +=i2
}
return n
}
func main() {
println(add(test())) //3
println(calc(test())) //3
}
4.1.5. 5.递归与回调¶
Go 语言中也可以使用相互调用的递归函数:多个函数之间相互调用形成闭环。
package main
import "fmt"
func main() {
callback(1, Add)
}
func Add(a, b int) {
fmt.Printf("The sum of %d and %d is: %d\n", a, b, a+b)
}
func callback(y int, f func(int, int)) {
f(y, 2)
}
4.1.6. 6.字符串的链式处理-操作与数据分离的设计技巧¶
package main
import (
"fmt"
"strings"
)
/*
字符串处理函数,传入字符串切片,和字符串切片处理链
*/
func StringProcess(list []string, chain []func(string) string) {
// 遍历每一个字符串
for index, str := range list {
// 第一个要处理的字符串
result := str
// 遍历每一个处理链
for _, proc := range chain {
//输入一个字符串进行处理,返回数据作为下一个处理链的输入
result = proc(result)
}
// 将结果放回到切片
list[index] = result
}
}
/*
自定义处理函数,自定义移除前缀的处理函数,移除字符串指定的前缀
*/
func removePrefix(str string) string {
return strings.TrimPrefix(str, "go")
}
/*
字符串处理主流程
*/
func main() {
// 待处理的字符串列表
list := []string{
"go huajinli1",
"go huajinli2",
"go huajinli3",
"go huajinli4",
"go huajinli5",
}
// 处理链函数
chain := []func(string) string{
removePrefix,
strings.TrimSpace,
strings.ToUpper,
}
// 处理字符串
StringProcess(list, chain)
// 输出处理好的字符串
for _, str := range list {
fmt.Println(str)
}
}
/*
HUAJINLI1
HUAJINLI2
HUAJINLI3
HUAJINLI4
HUAJINLI5
*/
package main
import "fmt"
func main() {
slice := []int{1, 2, 3, 4, 5, 7}
fmt.Println("slice = ", slice)
odd := filter(slice, isOdd) //函数当做值来传递
fmt.Println("奇数元素:", odd)
even := filter(slice, isEven) //函数当做值来传递
fmt.Println("偶数元素:", even)
}
type processFunc func(int) bool // 声明一个函数类型
// 判断元素是否是偶数
func isEven(integer int) bool {
if integer%2 == 0 {
return true
}
return false
}
// 判断元素是否是奇数
func isOdd(integer int) bool {
if integer%2 == 0 {
return false
}
return true
}
//根据奇偶来处理切片,组成新的切片
func filter(slice []int, f processFunc) []int {
var result []int
for _, value := range slice {
if f(value) {
result = append(result, value)
}
}
return result
}
/*slice = [1 2 3 4 5 7]
奇数元素: [1 3 5 7]
偶数元素: [2 4]*/
4.1.7. 7.函数的值传递和指针类型传地址¶
示例
package main
import (
"fmt"
"log"
)
//普通函数,值的副本传递
func functionA(num float64) float64 {
num *= num
return float64(num)
}
//指针类型函数,传递一个float64的指针类型,返回一个float64的指针类型
func functionB(num *float64) *float64 {
*num *= *num // 指针类型num处的值 * 指针类型num处的值
return num // 返回一个float64的指针类型
}
// 值函数,值的副本传递
func functionC(b bool) (b1 bool, e error) {
return !b, nil
}
// 指针函数, 传递一个bool的指针类型,返回一个bool的指针类型
func functionD(b *bool) *bool {
*b = !*b
return b
}
func main() {
n := 5.0
fmt.Println(functionA(n))
fmt.Println(n)
hu1 := functionB(&n) //传递一个float64的指针类型
fmt.Println(hu1) //打印指针地址
fmt.Println(*hu1) //打印hu1指针处的值
// 此时此刻已经改变了n指针地址处的原始值了
fmt.Println(n)
fmt.Println("-----------------------------------------------------")
b := true
fmt.Println(functionC(b))
fmt.Println(b)
hu2 := functionD(&b)
fmt.Println(hu2)
fmt.Println(*hu2)
fmt.Println(b)
h, err := functionC(false)
if err != nil {
log.Fatal("err",err)
}
fmt.Println(h)
}