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)
}