首页 > 其他分享 >(转)golang 函数

(转)golang 函数

时间:2023-01-15 16:22:13浏览次数:38  
标签:return 函数 int fmt golang func 返回值

原文:https://www.cnblogs.com/duoke360/p/15663943.html

golang函数简介

函数的go语言中的一级公民,我们把所有的功能单元都定义在函数中,可以重复使用。函数包含函数的名称、参数列表和返回值类型,这些构成了函数的签名(signature)。

go语言中函数特性

  1. go语言中有3种函数:普通函数、匿名函数(没有名称的函数)、方法(定义在struct上的函数)。receiver
  2. go语言中不允许函数重载(overload),也就是说不允许函数同名。
  3. go语言中的函数不能嵌套函数,但可以嵌套匿名函数。
  4. 函数是一个值,可以将函数赋值给变量,使得这个变量也成为函数。
  5. 函数可以作为参数传递给另一个函数。
  6. 函数的返回值可以是一个函数。
  7. 函数调用的时候,如果有参数传递给函数,则先拷贝参数的副本,再将副本传递给函数。
  8. 函数参数可以没有名称。

go语言中函数的定义和调用

函数在使用之前必须先定义,可以调用函数来完成某个任务。函数可以重复调用,从而达到代码重用。

go语言函数定义语法

func function_name( [parameter list] ) [return_types]
{
   函数体
}

语法解析:

  • func:函数由 func 开始声明
  • function_name:函数名称,函数名和参数列表一起构成了函数签名。
  • [parameter list]:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
  • 函数体:函数定义的代码集合。

go语言函数定义实例

定义一个求和函数

func sum(a int, b int) (ret int) {
	ret = a + b
	return ret
}

定义一个比较两个数大小的函数

func compare(a int, b int) (max int) {
	if a > b {
		max = a
	} else {
		max = b
	}
	return max
}

go语言函数调用

当我们要完成某个任务时,可以调用函数来完成。调用函数要传递参数,如何有返回值可以获得返回值。

func main() {
	s := sum(1, 2)
	fmt.Printf("s: %v\n", s)

	max := compare(1, 2)
	fmt.Printf("max: %v\n", max)
}

运行结果

s: 3
max: 2

golang函数的返回值

函数可以有0或多个返回值,返回值需要指定数据类型,返回值通过return关键字来指定。

return可以有参数,也可以没有参数,这些返回值可以有名称,也可以没有名称。go中的函数可以有多个返回值。

  1. return关键字中指定了参数时,返回值可以不用名称。如果return省略参数,则返回值部分必须带名称
  2. 当返回值有名称时,必须使用括号包围,逗号分隔,即使只有一个返回值
  3. 但即使返回值命名了,return中也可以强制指定其它返回值的名称,也就是说return的优先级更高
  4. 命名的返回值是预先声明好的,在函数内部可以直接使用,无需再次声明。命名返回值的名称不能和函数参数名称相同,否则报错提示变量重复定义
  5. return中可以有表达式,但不能出现赋值表达式,这和其它语言可能有所不同。例如return a+b是正确的,但return c=a+b是错误的。

go语言函数返回值实例

没有返回值

func f1() {
	fmt.Printf("我没有返回值,只是进行一些计算")
}

有一个返回值

func sum(a int, b int) (ret int) {
	ret = a + b
	return ret
}

多个返回值,且在return中指定返回的内容

func f2() (name string, age int) {
	name = "老郭"
	age = 30
	return name, age
}

多个返回值,返回值名称没有被使用

func f3() (name string, age int) {
	name = "老郭"
	age = 30
	return // 等价于return name, age
}

return覆盖命名返回值,返回值名称没有被使用

func f4() (name string, age int) {
	n := "老郭"
	a := 30
	return n, a
}

Go中经常会使用其中一个返回值作为函数是否执行成功、是否有错误信息的判断条件。例如return value,existsreturn value,okreturn value,err等。

当函数的返回值过多时,例如有4个以上的返回值,应该将这些返回值收集到容器中,然后以返回容器的方式去返回。例如,同类型的返回值可以放进slice中,不同类型的返回值可以放进map中。

但函数有多个返回值时,如果其中某个或某几个返回值不想使用,可以通过下划线_来丢弃这些返回值。例如下面的f1函数两个返回值,调用该函数时,丢弃了第二个返回值b,只保留了第一个返回值a赋值给了变量a

package main

import "fmt"

func f1() (int, int) {
	return 1, 2
}
func main() {
	_, x := f1()
	fmt.Printf("x: %v\n", x)
}

运行结果

x: 2

golang函数的参数

go语言函数可以有0或多个参数,参数需要指定数据类型

声明函数时的参数列表叫做形参,调用时传递的参数叫做实参。

go语言是通过传值的方式传参的,意味着传递给函数的是拷贝后的副本,所以函数内部访问、修改的也是这个副本。

go语言可以使用变长参数,有时候并不能确定参数的个数,可以使用变长参数,可以在函数定义语句的参数部分使用ARGS...TYPE的方式。这时会将...代表的参数全部保存到一个名为ARGS的slice中,注意这些参数的数据类型都是TYPE。

go语言函数的参数实例

go语言传参

// 形参列表
func f1(a int, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}

func main() {
	// 实参列表
	r := f1(1, 2)
	fmt.Printf("r: %v\n", r)
}

演示参数传递,按值传递

func f1(a int) {
	a = 200
	fmt.Printf("a1: %v\n", a)
}

func main() {
	a := 100
	f1(a)
	fmt.Printf("a: %v\n", a)
}

运行结果

a1: 200
a: 100

从运行结果可以看到,调用函数f1后,a的值并没有被改变,说明参数传递是拷贝了一个副本,也就是拷贝了一份新的内容进行运算。

mapsliceinterfacechannel这些数据类型本身就是指针类型的,所以就算是拷贝传值也是拷贝的指针,拷贝后的参数仍然指向底层数据结构,所以修改它们可能会影响外部数据结构的值。

package main

import "fmt"

func f1(a []int) {
	a[0] = 100
}

func main() {
	a := []int{1, 2}
	f1(a)
	fmt.Printf("a: %v\n", a)
}

运行结果

a: [1 2]
a: [100 2]

从运行结果发现,调用函数后,slice内容被改变了。

变长参数

package main

import "fmt"

func f1(args ...int) {
	for _, v := range args {
		fmt.Printf("v: %v\n", v)
	}
}
func f2(name string, age int, args ...int) {
	fmt.Printf("name: %v\n", name)
	fmt.Printf("age: %v\n", age)
	for _, v := range args {
		fmt.Printf("v: %v\n", v)
	}
}
func main() {
	f1(1, 2, 3)
	fmt.Println("------------")
	f1(1, 2, 3, 4, 5, 6)
	fmt.Println("------------")
	f2("tom", 20, 1, 2, 3)
}

运行结果

v: 1
v: 2
v: 3
------------
v: 1
v: 2
v: 3
v: 4
v: 5
v: 6
------------
name: tom
age: 20
v: 1
v: 2
v: 3

golang函数类型与函数变量

可以使用type关键字来定义一个函数类型,语法格式如下:

type fun func(int, int) int

上面语句定义了一个fun函数类型,它是一种函数类型,这种函数接收两个int类型的参数,并且返回一个int类型的返回值。

下面我们定义两个这样结构的两个函数,一个求和,一个比较大小:

func sum(a int, b int) int {
	return a + b
}

func max(a int, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}

下面定义一个fun函数类型,把summax赋值给它

package main

import "fmt"

type fun func(int, int) int

func sum(a int, b int) int {
	return a + b
}

func max(a int, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}

func main() {
	var f fun
	f = sum
	s := f(1, 2)
	fmt.Printf("s: %v\n", s)
	f = max
	m := f(3, 4)
	fmt.Printf("m: %v\n", m)
}

运行结果

s: 3
m: 4

golang高阶函数

go语言的函数,可以作为函数的参数,传递给另外一个函数,可以可以作为,另外一个函数的返回值返回。

go语言函数作为参数

package main

import "fmt"

func sayHello(name string) {
	fmt.Printf("Hello,%s", name)
}

func f1(name string, f func(string)) {
	f(name)
}

func main() {
	f1("tom", sayHello)
}

运行结果

Hello,tom

go语言函数作为返回值

package main

import "fmt"

func add(x, y int) int {
	return x + y
}

func sub(x, y int) int {
	return x - y
}

func cal(s string) func(int, int) int {
	switch s {
	case "+":
		return add
	case "-":
		return sub
	default:
		return nil
	}
}

func main() {
	add := cal("+")
	r := add(1, 2)
	fmt.Printf("r: %v\n", r)

	fmt.Println("-----------")

	sub := cal("-")
	r = sub(100, 50)
	fmt.Printf("r: %v\n", r)
}

运行结果

r: 3
-----------
r: 50

golang匿名函数

go语言函数不能嵌套,但是在函数内部可以定义匿名函数,实现一下简单功能调用。

所谓匿名函数就是,没有名称的函数。

语法格式如下:

func (参数列表)(返回值)

当然可以既没有参数,可以没有返回值

匿名函数实例

func main() {
	max := func (a int, b int) int {
		if a > b {
			return a
		} else {
			return b
		}
	}

	i := max(1, 2)
	fmt.Printf("i: %v\n", i)
}

运行结果

i: 2

自己执行

func main() {
	// 自己执行
	func(a int, b int) {
		max := 0
		if a > b {
			max = a
		} else {
			max = b
		}
		fmt.Printf("max: %v\n", max)
	}(1, 2)
}

运行结果

max: 2

golang闭包

闭包可以理解成定义在一个函数内部的函数。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。或者说是函数和其引用环境的组合体。

闭包指的是一个函数和与其相关的引用环境组合而成的实体。简单来说,闭包=函数+引用环境。 首先我们来看一个例子:

package main

import "fmt"

// 返回一个函数
func add() func(int) int {
	var x int
	return func(y int) int {
		x += y
		return x
	}
}

func main() {
	var f = add()
	fmt.Println(f(10))
	fmt.Println(f(20))
	fmt.Println(f(30))
	fmt.Println("-----------")
	f1 := add()
	fmt.Println(f1(40))
	fmt.Println(f1(50))
}

运行结果

10
30
60
-----------
40
90

变量f是一个函数并且它引用了其外部作用域中的x变量,此时f就是一个闭包。 在f的生命周期内,变量x也一直有效。 闭包进阶示例1:

package main

import "fmt"

func add(x int) func(int) int {
	return func(y int) int {
		x += y
		return x
	}
}
func main() {
	var f = add(10)
	fmt.Println(f(10))
	fmt.Println(f(20))
	fmt.Println(f(30))

	fmt.Println("----------")

	f1 := add(20)
	fmt.Println(f1(40))
	fmt.Println(f1(50))
}

运行结果

20
40
70
----------
60
110

闭包进阶示例2:

func makeSuffixFunc(suffix string) func(string) string {
	return func(name string) string {
		if !strings.HasSuffix(name, suffix) {
			return name + suffix
		}
		return name
	}
}

func main() {
	jpgFunc := makeSuffixFunc(".jpg")
	txtFunc := makeSuffixFunc(".txt")
	fmt.Println(jpgFunc("test")) 
	fmt.Println(txtFunc("test")) 
}

运行结果

test.jpg
test.txt

闭包进阶示例3:

func calc(base int) (func(int) int, func(int) int) {
	add := func(i int) int {
		base += i
		return base
	}

	sub := func(i int) int {
		base -= i
		return base
	}
	return add, sub
}

func main() {
	f1, f2 := calc(10)
	fmt.Println(f1(1), f2(2)) 
	fmt.Println(f1(3), f2(4)) 
	fmt.Println(f1(5), f2(6)) 
}

运行结果

11 9
12 8
13 7

闭包其实并不复杂,只要牢记闭包=函数+引用环境

golang递归

函数内部调用函数自身的函数称为递归函数。

使用递归函数最重要的三点:

  1. 递归就是自己调用自己。
  2. 必须先定义函数的退出条件,没有退出条件,递归将成为死循环。
  3. go语言递归函数很可能会产生一大堆的goroutine,也很可能会出现栈空间内存溢出问题。

go语言递归实例

阶乘

package main

import "fmt"

func a(n int) int {
	// 返回条件
	if n == 1 {
		return 1
	} else {
		// 自己调用自己
		return n * a(n-1)
	}
}

func main() {
	n := 5
	r := a(n)
	fmt.Printf("r: %v\n", r)
}

运行结果

r: 120

斐波那契数列

它的计算公式为f(n)=f(n-1)+f(n-2)f(2)=f(1)=1

package main

func f(n int) int {
	// 退出点判断
	if n == 1 || n == 2 {
		return 1
	}
	// 递归表达式
	return f(n-1) + f(n-2)
}

func main() {
	r := f(5)
	fmt.Printf("r: %v\n", r)
}

运行结果

r: 5

golang defer语句

go语言中的defer语句会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序进行执行,也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行。stack

defer特性

  1. 关键字 defer 用于注册延迟调用。
  2. 这些调用直到 return 前才被执。因此,可以用来做资源清理。
  3. 多个defer语句,按先进后出的方式执行。
  4. defer语句中的变量,在defer声明时就决定了。

defer用途

  1. 关闭文件句柄
  2. 锁资源释放
  3. 数据库连接释放

go语言defer语句实例

查看执行顺序

func main() {
	fmt.Println("start")
	defer fmt.Println("step1")
	defer fmt.Println("step2")
	defer fmt.Println("step3")
	fmt.Println("end")
}

运行结果

start
end
step3
step2
step1

golang init函数

golang有一个特殊的函数init函数,先于main函数执行,实现包级别的一些初始化操作。

init函数的主要特点

  • init函数先于main函数自动执行,不能被其他函数调用;
  • init函数没有输入参数、返回值;
  • 每个包可以有多个init函数;
  • 包的每个源文件也可以有多个init函数,这点比较特殊;
  • 同一个包的init执行顺序,golang没有明确定义,编程时要注意程序不要依赖这个执行顺序。
  • 不同包的init函数按照包导入的依赖关系决定执行顺序。

golang 初始化顺序

初始化顺序:变量初始化->init()->main()

实例

package main

import "fmt"

var a int = initVar()

func init() {
	fmt.Println("init2")
}

func init() {
	fmt.Println("init")
}

func initVar() int {
	fmt.Println("init var...")
	return 100
}

func main() {
	fmt.Println("main...")
}

运行结果

init var...
init2
init
main...

标签:return,函数,int,fmt,golang,func,返回值
From: https://www.cnblogs.com/liujiacai/p/17053662.html

相关文章

  • 写了个判断文件是否被锁定的函数 --- 有用!
    今天在工程中要用到这个功能,把它写出来,如果你有用得着的地方,直接Ctrl+C去,呵呵.函数如下:boolIsFileLocked(LPCTSTRszFileName){if(szFileName==NULL)returnfalse;HANDLE......
  • [SQL] Hive日期时间函数整理
    1.日期时间常量current_date:获取当前日期current_timestamp:获取当前时间2.日期时间函数2.1获取日期时间指定部分获取日期指定部分extract(fieldFROMsource)-......
  • 欧拉函数的一些题
    欧拉函数及相关定理1.P2158[SDOI2008]仪仗队原题链接题目大意在一个从\((0,0)\)到\((n-1,n-1)\)的方阵中,有多少点能从原点“看到”分析一个点\(D\)能从原点“看......
  • golang实现的一个小游戏–猜数字
    随机生成一个数字,输入一个数字看是否匹对,匹配则结速,反之提示是大了还是小了,代码如下:packagemainimport("bufio""fmt""math/rand""os""strconv""time")var......
  • Python 中的函数参数
    在通常情况下,定义函数时,函数的参数个数是预先确定的。例如,编写计算两个数相加的函数add(a,b),代码如下:defadd(a,b):returna+bsum=add(1,2)在第1行,定义了函数......
  • 【数据库】PostgreSQL/PgSql-根据模式名和字段名查询有该字段的所有表信息【通过表元
    【数据库】PostgreSQL/PgSql-根据模式名和字段名查询有该字段的所有表信息【通过表元数据信息和函数实现】...哥们要飞于2022-08-2314:51:00发布304收藏文章标签:数......
  • python def函数总结
    简单无参函数编写脚本test1.pydefregister_user():"""docstring"""#描述函数的功能print("Welcome!")register_user()#调用函数执行脚本test1.py输出结果We......
  • 解决Clion一个项目下多个main函数运行问题
    解决Clion一个项目下多个main函数运行问题第一种解决方案手动添加1.在本项目的CMakeLists.txt文件夹下添加如下:2.在右上角配置运行文件第二种解决方案下载插件:C/......
  • python教程6--自定义函数,数据类型转换,解方程
    本文主要讲解点如下:简单函数数据类型转换空函数自定义绝对值函数自定义函数检查参数类型函数返回多个值求解ax2+bx+c=0的根具体代码如下:'函数相关'__author__='mo......
  • [VueJsDev] 基础知识 - Node.js常用函数
    Node.js常用函数总结常用node函数用的ESM模块。//package.json"type":"module",Func.1:读取文件-同步/异步读取path文件​​ESM模式​​同步读取文件import{......