Golang——函数

函数

2.1 函数

func funcName(param-list)(result-list){
	fuction body
}

如果没有返回参数,(result-list)可以省略,如果只有一个返回值,可以只写类型,不写括号

func funcName(para-list) type {
	function body
}

go的返回值如果直接在result-list内声明,那么最后的return可以不带参数名

func add(a, b int) (sum int){
	sum = a + b // 这里相当于sum已经声明过了,直接赋值即可
	return
}

Golang函数不支持默认参数,不支持函数重载,不支持命名函数的嵌套定义,但支持嵌套匿名函数

多值返回

func swap(a, b int)(int ,int){
	return b, a
}

实参到形参的传递

Go函数实参到形参永远是值拷贝,要么是值拷贝,要么是指针值拷贝。

func chvalue(a int) int{
	a = a + 1
	return a
}
// 实参不会改变

func chpointer(a *int) {
	*a = *a + 1
	return
}
// 实参地址内的数值+1

不定参数

param ...type

  • 不定参数必须类型相同
  • 不定参数必须是最后一个参数
  • 不定参数在函数体内相当于切片(slice)
  • 切片可以作为参数传递给不定参数,但是切片后面要加上…
// 定义方法 name ...type
func sum(arr ...int)(sum int){
	for _, v := range arr{
		sum += v
	}
	return
}

// 传递方法
func main(){
	slice := []int{1,2,3,4}
	sum(slice...) //切片后必须跟...
	// 数组不能作为实参传入不定参数
}

2.2 函数签名和匿名函数

函数签名也叫函数类型

两个函数,如果参数列表类型、顺序相同,返回列表类型、顺序也相同,那么就说他们的函数类型完全相同
可以用type定义函数类型
type Op func(int, int) int// 定义读入两个int,返回一个int的函数类型为Op
函数类型和map、slice、chan一样,实际函数类型变量和函数名都可以当做指针变量,指针指向函数代码开始位置,没有初始化(没有函数体)的函数类型的变量是nil

匿名函数

匿名函数可以看做函数字面量,所有直接使用函数的地方都可以用匿名函数代替,匿名函数可以直接赋值给函数变量,可以当实参,也可以作为返回值,还可以直接被调用(最后加括号输入实参)

var sum = func(a, b int) int{
	return a + b
}
// 匿名函数相当于右值(字面量),赋值给函数变量sum

2.3 defer

Go函数里提供了defer关键字,可以注册多个延迟调用,这些调用遵循先进后出(FILO)

func main(){
	defer func(){
		fmt.println("first")
	}()
	defer func(){
		fmt.println("second")
	}()
	fmt.println("function body")
}

结果是

function body
second
first

first先被注册,压入栈底,然后second注册,处于栈顶,根据出栈顺序出栈

defer后必须是函数或方法的调用,不能是语句,否则会报错
defer时函数的实参是注册时通过值传递拷贝进去的,这就意味着在程序顺序运行到defer时,实参的数值是多少,最后出栈的时候就是多少,与后续的参数数值的改变无关。

func f() int{
	a := 0
	defer func(i int){
		fmt.println(i)
	}(a)
	a++
	retnurn a
}
最终结果
0

在匿名函数后面加括号是匿名函数传递参数的方法,相当于一次调用

那么既然defer需要先注册,当函数体执行完毕后逐一出栈,那么就很好理解,如果defer在return后,或者函数体内主动调用了os.Exit(int)退出进程,由于没有注册,那么对应代码段就不会被执行,直接退出函数体或者结束进程。

使用场景

诸如文件打开之后需要close的此类操作,很多时候有许多情况会return,但是每个地方都要写close就很麻烦,那么可以在开始处就写一个defer func(){close}的函数,那么当函数执行完毕,最后总会执行关闭文件的操作。

副作用

可能造成资源释放推迟,不能及时释放
如果位置不当可能导致panic,一般defer放在错误检查语句之后。

2.4 闭包

闭包是go里可以实现全局变量的一种方法

package main

import "fmt"

func operate(base int) (func(int) int, func(int) int) {
	fmt.Println("the base is ", base)
	add := func(number int) int {
		base += number
		return base
	}
	sub := func(number int) int {
		base -= number
		return base
	}
	return add, sub
}

func main() {
	// a1, s1处于同一个闭包中,共享闭包中的base变量
	add, sub := operate(0)
	fmt.Println(add(1))
	fmt.Println(sub(2))
	/*
		the base is  0
		1
		-1
	*/
}

每实例化一个operate闭包返回两个方法,一个加一个减,两个函数共享一个base,再实例一个operate返回的两个函数会共享另外的base。

2.5方法

函数的声明方式是

func funcName(para paratype) returnTyle {}

方法的声明方式是

func (variable_name variable_data_type) function_name(para) [return_type]{}

第一个括号内填入的是命名类型或者结构体的值或者指针,大致相当于在函数名前加了一个括号

package main

import (
	"fmt"
)

type Circle struct{
	radius float64
}

func main() {
	fmt.Println("hello!")
	var c1 = Circle{3}
	fmt.Println(c1.getRadius())
	fmt.Println(c1.getArea())
	
}

func(c Circle) getRadius() float64{
	return c.radius
}

func(c Circle) getArea() float64{
	return 3.14* c.radius * c.radius
}

func(c *Circle) setRadius(r float64){
	c.Radius = r
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

volcanical

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值