go语言 函数和包

时间:2024-07-07 07:14:23

一、函数

在Go语言中,函数是执行特定任务的自包含代码块。

1.函数的定义

函数通过func关键字定义,格式如下:

func 函数名(形参 形参类型, 形参 形参类型) 返回值类型 {
 函数体
 return 返回值
}

2.基础函数类型

  • 无参数无返回值
  • 单个参数,无返回值
  • 多个相同类型参数,无返回值
  • 多个不同类型参数,无返回值
  • 多个参数,一个返回值
  • 多个参数,多个返回值
package main

import "fmt"

func main() {
	demo01()
	//demo02("d") // 类型不匹配
	demo02(2)
	demo03(1, 2)
	demo04(1, "A")
	var res = demo05(1, 2)
	fmt.Println("a+b:", res)

	var res1, res2 = demo06(1, 1)
	fmt.Println(res1, res2)
}

// 无参数无返回值
func demo01() {
	fmt.Println("hello world")
}

// 单个参数,无返回值
func demo02(a int) {
	fmt.Println("a:", a)
}

// 多个相同类型参数,无返回值
func demo03(a, b int) {
	fmt.Println("a+b:", a+b)
}

// 多个不同类型参数,无返回值
func demo04(a int, b string) {
	fmt.Println("a:", a)
	fmt.Println("b:", b)
}

// 多个参数,一个返回值
func demo05(a, b int) int {
	return a + b
}

// 多个参数,多个返回值
func demo06(a, b int) (int, bool) {
	if a+b > 3 {
		return a + b, true
	} else {
		return a * b, false
	}
}

3.特殊函数类型

  • 匿名函数test06展示了如何在Go中定义匿名函数,即没有函数名的函数。
  • 函数作为一等公民f变量可以存储函数,test11返回一个函数作为其结果。
  • 命名返回值test10展示了如何使用命名返回值,这有助于提高代码的可读性。
  • 闭包test12是一个闭包示例,它捕获并使用外部作用域的变量。
  • 函数作为参数test14接受一个函数作为参数,并在函数体内调用它。
  • 类型重命名MyFuncfunc(string) (int, int)类型的别名。
package main

import "fmt"

func main() {
	demo01()

	// 函数作为一等公民
	var demo02 = func(a, b int) int {
		return a + b
	}
	var res = demo02(15, 16)
	fmt.Println(res)

	var res1, res2 = demo03(16, 17)
	fmt.Println(res1, res2)

	// 闭包
	var ff = demo04(15)
	ff()

	// 函数作为参数
	var f1 = func(a int) {
		fmt.Println(a)
	}
	demo05(15, f1)

	// 类型重命名
	type StringProcessor func(string) string
	processor := StringProcessor(func(input string) string {
		return "Processed: " + input
	})
	result := processor("Input")
	fmt.Println(result)

}

// 匿名函数
func demo01() {
	fmt.Println("demo01--start")
	// 定义匿名函数并立即执行
	func() {
		fmt.Println("demo01--inner")
	}()
	fmt.Println("demo01--end")
}

// 命名返回值
func demo03(a, b int) (sum int, flag bool) {
	sum = a + b
	flag = true
	//return sum, flag   // 可以指定
	return // 也可以不在指定
}

// 闭包
func demo04(x int) func() {
	x = 666
	f := func() {
		fmt.Println("我是内部函数", x)
	}
	return f
}

// 函数作为参数
func demo05(a int, f func(i int)) {
	f(a)
}

4.装饰器函数

  • Go语言虽然没有像一些其他语言(例如Python)那样的装饰器语法,但是可以通过闭包来实现类似的功能。

  • 装饰器通常用于在不修改原始函数代码的情况下增加函数的功能。

  • 示例

package main

import (
	"fmt"
	"time"
)

// 普通函数
func sayHello(name string) string {
	time.Sleep(time.Second) // 延迟1秒
	return "Hello " + name
}

// 自定义装饰器,计时功能
func timeTrack(fn func(string) string) func(string) string {
	return func(name string) string {
		startTime := time.Now()              //  记录开始时间
		result := fn(name)                   //  调用原始函数
		elapsedTime := time.Since(startTime) //  计算经过时间
		fmt.Printf("耗时: %s \n", elapsedTime)
		return result
	}
}
func main() {
	// 使用装饰器增强原始函数
	enhanceSayHello := timeTrack(sayHello)

	helloMessage := enhanceSayHello("world")
	fmt.Println(helloMessage)
}

二、包

在Go语言中,包(package)是组织源代码的基本单位,它有助于代码的可重用性和可读性

1.包规则

  1. 导出规则:如果一个函数、变量或类型的名称以大写字母开头,它就是导出的(exported),这意味着它可以在包外部被访问和使用。如果以小写字母开头,则它在包外部是不可见的。
  2. 包名一致性:在同一个文件夹下的所有Go源文件应该属于同一个包,并且包名通常建议与文件夹名相同。这是为了保持代码的清晰和易于理解。
  3. 包内部可见性:在同一个包内的所有源文件共享相同的包级作用域,这意味着这些文件中的所有变量、函数和类型都像是在同一个文件中一样可见。
  4. 使用包:要使用其他包中的导出成员,需要导入对应的包,并通过包名来引用它们。
  5. 导入包:使用import关键字来导入包。导入时,通常使用包的全路径名,例如import "demo/common"
  6. 导入并重命名包:如果包名冲突或者为了方便引用,可以在导入时为包指定一个新的名称,例如import cv1 "demo/common/v1"
  7. 一次导入多个包:可以通过一对花括号来一次导入多个包,这样可以保持代码的整洁。

2.示例

  • 目录结构

    • demo/
      ├── common/
      │   ├── v1/          # v1 是 common 包的一个子目录,表示版本1
      │   │   └── demo01.go # demo01.go 是 common 包 v1 版本的实现文件
      │   ├── demo02.go    # demo02.go 是 common 包的一部分,不在任何子目录中
      │   └── demo01.go    # 这是 common 包的另一个实现文件,可能与 v1 版本不同
      └── main.go          # main.go 是 main 包的入口文件,通常包含 main 函数
      └── go.mod           # go.mod 是 Go 模块的配置文件,记录模块的依赖关系
      
  • 文件内容

    • // main.go
      package main
      
      // 导入标准库中的fmt包
      import "fmt"
      
      // 一次导入多个包
      import (
      	"demo/common"
      	cv1 "demo/common/v1" // // 导入包并重命名
      )
      
      func main() {
      	// 使用fmt包的Println函数
      	fmt.Println("Hello, world!")
      
      	res1 := common.Add(1, 2)
      	fmt.Println(res1)
      
      	res2 := cv1.Mul(4, 5) // 使用重命名的包
      	fmt.Println(res2)
      }
      
      
    • // common/demo01.go
      
      package common
      func Add(a, b int) int {
      	return a + b
      }
      
    • // common/demo02.go
      
      package common
      func Addd(a, b int) int {
      	return Add(a, b) + b
      }
      
    • // common/v1/demo01.go
      
      package v1
      func Mul(a, b int) int {
      	return a * b
      }