函数的定义
函数的定义使用 func 关键字定义
func 函数名(参数)(返回值){
函数体
}
函数名:由 字母、数字、下划线 组成,但函数名的第一个字母不能是数字,在同一个包内,函数名也称 不能重复;
参数由:参数变量 和 参数变量的类型 组成,例如:(amount int,name string)
,多个参数之间使用 ,
分隔,可以没有参数;当参数比较长的时候,可以定义为结构体。
返回值:由变量和类型的形式,返回值变量可以在函数体中被使用,此时 return 语句后可为空,将定义的返回变量给返回,也就是将 return 变量值返回:
func intSum(x int,y int) (result int) {
result = x + y
return // return语句后可为空
}
返回值参数还可以只有类型的形式,这个时候 return 语句后不能为空
// 只有int类型,没有变量
func intSum(x int,y int) int {
return x + y // 这个时候return语句后不能为空
}
函数还可以返回多个值,或者没有返回值
// 返回两个int类型的值
func test () (int,int) {
return 1,2
}
函数的参数
如果相邻变量的类型相同,则可以省略类型
// x类型也是int,和y一样
func intSum(x, y int) int {
return x + y
}
还可以声明为可变参数,在参数名后加 …
来标识,可变参数通常要作为函数的最后一个参数
func main() {
ret := intSum(10, 20)
fmt.Println(ret)
}
// 求和
func intSum(x ...int) int {
fmt.Println(x) //x是一个切片
sum := 0
for _, v := range x {
sum = sum + v
}
return sum
}
声明指针类型的参数,传入的值必须是指针
// Person 是一个结构体
type Person struct {
name string
age int8
}
func test(p *Person) {
}
func main() {
p1 := &Person{
name: "张三",
age: 30,
}
test(p1)
}
函数参数必须传,但是参数可以没有被使用
func test(name string) { // name 没有被使用是允许的
fmt.Println("123")
}
func main() {
test("123") // 但是参数必须传递
}
函数参数的默认值是如何设置的呢?
方式一:使用中间对象的方式
// 默认参数的选项,中间对象
type TeaOptions struct {
heat bool
}
// 创建默认参数对象
func NewDaulft() *TeaOptions {
return &TeaOptions{
heat: false, // 默认不加热
}
}
type Tea struct {
name string
heat bool
}
// 创建具体对象
func NewTea(name string, ops *TeaOptions) (*Tea, error) {
return &Tea{
name: name,
heat: ops.heat,
}, nil
}
func (t Tea) getTea() {
fmt.Printf("name:%s , heat:%t ", t.name, t.heat)
}
func main() {
// 使用默认参数
tea1, _ := NewTea("tea1", NewDaulft())
tea1.getTea()
// 不使用默认参数,创建TeaOptions对象传参
tea2, _ := NewTea("tea2", &TeaOptions{heat: true})
tea2.getTea()
}
方式二:使用 选项模式,该模式便于扩展,可以使用设计模式中的选项模式来创建对象
type config struct {
logicalRegionIdKey string
logicalRegionNameKey string
}
type Option func(cfg *config)
// WithSetLogicalRegionIdKey 修改默认值
func WithSetLogicalRegionIdKey(key string) Option {
return func(cfg *config) {
cfg.logicalRegionIdKey = key
}
}
func NewLogicalRegionConverter(name string, opts ...Option) {
// 默认值
cfg := config{
logicalRegionIdKey: "logical_region_id",
logicalRegionNameKey: "logical_region_name",
}
if opts != nil && len(opts) > 0 {
for _, opt := range opts {
opt(&cfg)
}
}
fmt.Println(name, cfg.logicalRegionIdKey, cfg.logicalRegionNameKey)
}
func main() {
NewLogicalRegionConverter("区域配置")
NewLogicalRegionConverter("区域配置", WithSetLogicalRegionIdKey("logical_region_id_不是默认值"))
}
函数的返回值
函数可以有多个返回值,有多个返回值时必须用 ()
将所有返回值包裹起来
// (int,int)
func calc(x, y int) (int, int) {
sum := x + y
sub := x - y
return sum, sub
}
可以对返回值进行命名,在函数体中直接使用这些变量,最后通过 return
关键字返回
func calc(x, y int) (sum, sub int) {
sum = x + y
sub = x - y
return
}
函数的调用
通过 函数名()
的方式调用函数,调用有返回值的函数时,可以不接收其返回值
func main() {
// 调用
sayHello()
ret := intSum(10, 20)
fmt.Println(ret)
}
函数参数有时候很长,需要换行显示,最后一个参数需要有逗号,这样好像也没关系
func QueryByPage(
logicalRegionId int,
page, pageSize int, // 需要有逗号
) {
// 实现
}
函数的作用域
在函数中可以访问到全局变量,也就是定义在函数外部的全局变量,在函数内部定义的局部变量只有当前函数作用域中生效,如果局部变量和全局变量重名,优先访问局部变量。
函数类型的变量
可以将变量声明为函数类型
type calculation func(int, int) int
// 例如,就是calculation类型
func add(x, y int) int {
return x + y
}
func main() {
var c calculation // 声明一个calculation类型的变量c
c = add // 把add赋值给c
fmt.Printf("type of c:%T\n", c) // type of c:main.calculation
fmt.Println(c(1, 2)) // 像调用add一样调用c
f := add // 将函数add赋值给变量f1
fmt.Printf("type of f:%T\n", f) // type of f:func(int, int) int
fmt.Println(f(10, 20)) // 像调用add一样调用f
}
函数作为参数
既然函数可以作为变量类型,并且用于赋值,那么函数自然可以传递给函数的参数
func add(x, y int) int {
return x + y
}
// 接收函数类型为:func(int, int) int的函数
func calc(x, y int, op func(int, int) int) int {
return op(x, y)
}
func main() {
ret2 := calc(10, 20, add)
fmt.Println(ret2) //30
}
函数作为返回值类型
同理,返回值类型也可以定义为函数类型
func add(x, y int) int {
return x + y
}
// 返回类型:func(int, int) int
func do() (func(int, int) int) {
return add
}
匿名函数
我们把没有函数名称的函数,叫做匿名函数,这个跟 php 的匿名函数类似
func main() {
// 将匿名函数保存到变量
add := func(x, y int) {
fmt.Println(x + y)
}
add(10, 20) // 通过变量调用匿名函数
//自执行函数:匿名函数定义完加()直接执行
func(x, y int) {
fmt.Println(x + y)
}(10, 20)
}
闭包
闭包是一个 函数 和 与其相关的引用环境 组合而成的实体,就好比是封闭的一个包,有点像类的,里面有属性和方法。
// 类似于一个类:属性+方法
func adder(x int) func(int) int {
// 属性
var z int
// 函数
return func(y int) int {
z = y + x + z
x++
return z
}
}
func main() {
// 属性x、z在f对象的整个声明周期内有效
var f = adder(10) // 构造函数初始化
fmt.Println(f(20)) //30 调用对象的方法
fmt.Println(f(50)) //91
}
defer 语句
defer 语句会将其后面跟随的语句进行延迟处理,函数即将返回时,按 defer
定义的逆序进行执行
// 输出:start end 3 2 1
func main() {
fmt.Println("start")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("end")
}
评论 (0)