Golang面向过程编程-函数
Golang面向过程编程-函数
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.什么是函数
简单的说函数的作用就是把程序里多次调用的相同的代码部分定义成一份,然后起个名字,所有的调用都只用这个名字就可以了。修改代码时,只需要改变函数体内的代码即可。Go 语言最少有个 main() 函数。你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。函数声明告诉了编译器函数的名称,返回类型,和参数。Go语言标准库提供了多种可动用的内置的函数。
二.函数的特点
1>.减少重复代码;
2>.使程序变得可扩展;
3>.使程序变得易维护;
三.函数的返回值
说简单点就是函数执行完毕之后,会用关键字return返回一个value,这个value就是返回值。案例如下:
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" func Max(a, b int) int { //其中关键字“func”是声明一个叫Max的函数名,“a”和“b”是传递的参数,第一个int是指参数的类型,第二个int是指返回值的类型
if a > b {
return a //表示当“a”大于“b”时,返回函数“a”
}else {
return b //否则就返回“b”,其实这个else可以不用写,因为他们的执行结果是等效的。
}
} func main() { //定义一个主函数,一个go程序运行起来不能没有主函数,当主函数结束时,就意味着程序的结束。
res := Max(100,200) //调用函数,需要按照你自己定义的函数类型进行传参数,否则会编译报错哟!用变量res来接受函数的返回值。
fmt.Printf("相比之下,最大的数字是:【%d】\n",res)
} #以上代码执行结果如下:
相比之下,最大的数字是:【200】
四.函数的传参姿势
函数定义时指出,函数定义时有参数,该变量可称为函数的形参。形参就像定义在函数体内的局部变量。 但当调用函数,传递过来的变量就是函数的实参,函数可以通过两种方式来传递参数:
a>.值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
b>.引用传递:是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
在默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt"
/*
传递类型 描述
值传递 值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递 引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
*/ func SwapName(a string, b string) (string, string) { //该函数主要的功能就是将字符串的位置发生了改变,前后颠倒了一下。\
return b ,a
} func Swap(p *string,q *string) { //这个函数就牛逼了,它是并每一交换字符串的位置,而是直接将变量名的值给调换了。
var temp string
temp = *p
*p = *q
*q = temp
} func main() {
Name_1 := "尹正杰"
Name_2 := "饼干"
x,y := SwapName(Name_1,Name_2)
fmt.Println(x,y) //只是将变量的位置交换了一下,我们成这种传参方式为值传参。
fmt.Printf("执行Swap函数之前Name_1=[%s],Name_2=[%s]\n",Name_1,Name_2)
Swap(&Name_1,&Name_2) //并没有交换变量的位置,而是交换了变量的value,我们成这种传参方式叫做引用传参。
fmt.Printf("执行Swap函数之后Name_1=[%s],Name_2=[%s]\n",Name_1,Name_2)
} #以上代码执行结果如下:
饼干 尹正杰
执行Swap函数之前Name_1=[尹正杰],Name_2=[饼干]
执行Swap函数之后Name_1=[饼干],Name_2=[尹正杰]
1.不定参数的传递
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"fmt"
"reflect"
) func SpecificTypes(args ...int) {
for _, arg := range args {
fmt.Printf("当前参数是【%v】,其类型是【%v】\n",arg,reflect.TypeOf(arg))
}
} func main() {
list_1 := []int{5,4,3,2,1}
for _,v := range list_1{
SpecificTypes(v) //传递了5个参数进去
}
Num_1 := 100
Num_2 := 200
SpecificTypes(Num_2,Num_1) //只传递了2个int类型的参数进去
} #以上代码执行结果如下:
当前参数是【5】,其类型是【int】
当前参数是【4】,其类型是【int】
当前参数是【3】,其类型是【int】
当前参数是【2】,其类型是【int】
当前参数是【1】,其类型是【int】
当前参数是【200】,其类型是【int】
当前参数是【100】,其类型是【int】
2.任意类型的不定参数
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"fmt"
"reflect"
) func AnyType(args ...interface{}) { //interface可谓大胃王,可以接受任何的数据类型。
fmt.Println(args)
for _,arg := range args{
fmt.Printf("当前参数是【%v】,其类型是【%v】\n",arg,reflect.TypeOf(arg))
}
} func main() {
ArrayInt := []int{100,200,300}
ArrayString := []string{"yin","zheng","jie"}
ArrayBytes := []byte{'a','b','c'}
AnyType(ArrayInt,ArrayString,ArrayBytes) //可以传递任意类型的数据。
} #以上代码执行结果如下:
[[100 200 300] [yin zheng jie] [97 98 99]]
当前参数是【[100 200 300]】,其类型是【[]int】
当前参数是【[yin zheng jie]】,其类型是【[]string】
当前参数是【[97 98 99]】,其类型是【[]uint8】
五.匿名函数
匿名函数是指不需要定义函数名的一种函数实现方式。1958年LISP首先采用匿名函数。 在Go里面,函数可以像普通变量一样被传递或使用,Go语言支持随时在代码里定义匿名函数。 匿名函数由一个不带函数名的函数声明和函数体组成。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
1>.匿名函数案例一,求某个数字的平方根。
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"fmt"
"math"
) func main() {
GetSqrt := func(num float64)float64 { //定义一个名称叫做GetSqrt的匿名函数,特点是用func关键字定义时没有函数名,只有函数形参和返回值类型。
return math.Sqrt(num) //代码的结构体可以直接使用形参里面的参数,并将结果传给GetSqrt变量。
}
fmt.Println(GetSqrt(100)) //计算100的平方根。
fmt.Println(GetSqrt(64))
fmt.Println(GetSqrt(25))
} #以上代码执行结果如下:
10
8
5
2>.匿名函数案例二,对数字进行排序;
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"sort"
"fmt"
) func main() {
num := []int{2,400,1,5,3,9,700,6} //定义一个无序的切片;
sort.Slice(num, func(i, j int) bool { //利用sort包给字符串排序
return num[i] > num[j]
})
fmt.Println(num)
} #以上代码执行结果如下:
[700 400 9 6 5 3 2 1]
3>.匿名函数案例三,对字母进行排序;
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"sort"
"fmt"
) type student struct { //定义一个机构体;
id int
name string
} func main() {
str := []student{} //声明一个结构体
str = append(str,student{
name:"EEEEE",
id:1,
}) str = append(str,student{
name:"CCCC",
id:2,
}) str = append(str,student{
name:"DDDDDD",
id:3,
}) sort.Slice(str, func(i, j int) bool {
return str[i].name < str[j].name //按照字母排序
})
fmt.Println(str) sort.Slice(str, func(i, j int) bool {
return str[i].id < str[j].id //按照数字排序
})
fmt.Println(str)
} #以上代码执行结果如下:
[{2 CCCC} {3 DDDDDD} {1 EEEEE}]
[{1 EEEEE} {2 CCCC} {3 DDDDDD}]
六.递归函数
简单的说递归函数就是自己调用自己,但是你需要一定一个结束条件。那么有的小伙伴会问了,为什么要指定结束条件呢?因为调用递归函数的时候都会在系统内存中重新开辟出一块内存,如果你一直调用它不去给它一个终止点的话,物理内存很快就会被撑爆的。
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" func FibonacciSequence(n int64) int64 { //这是定义斐波拉契数列的递归函数,其中数字n表示结束位置。
if n == 1 || n == 2 {
return 1
}
return FibonacciSequence(n-1) + FibonacciSequence(n-2) //指定结束条件
} func main() {
fmt.Println(FibonacciSequence(40)) //第40个数字所对应的值。
} #以上代码执行结果如下:
102334155
七.嵌套函数
嵌套函数,就是指在某些情况下,您可能需要将某函数作为另一函数的参数使用。
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"strings"
"fmt"
) func Toupper(s string) string { //还函数是讲字母从小写转换成大写。
return strings.Map(func(r rune) rune { //类似python中的嵌套函数.即在函数里在定义了一个匿名函数。
return r - 32
},s)
} func main() {
fmt.Println(Toupper("yinzhengjie"))
} #以上代码执行结果如下:
YINZHENGJIE
八.闭包函数
闭包是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)。 “官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
我们知道return可以返回一个字符串或是一个整数型当然也是可以返回一个函数,我们利用它可以返回函数的特性,可以在调用该函数的时候拿到返回的函数,再去执行返回的函数,最终得到我们想要的结果,要注意的是这个返回的函数的是可以获取到定义它的函数的环境变量。拥有这种定义方式和调用方法的函数,我们称之为比包函数。
1>.利用闭包函数求和;
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" func SummationOperation(n int64) func(int64) int64 { //定义一个函数,并且返回值应该是个函数。
return func(m int64) int64 { //返回一个匿名函数
return m + n //该匿名函数只有“m”形参,但是它可以获取到它的SummationOperation的一个形参“n”的值。
}
} func main() {
sum := SummationOperation(100) //调用函数SummationOperation函数,由于它返需要返回一个匿名函数,因此我们需要用一个变量去接收。
fmt.Println(sum(20)) //由于匿名函数需要传入一个“int64”的数据类型进行相加操作,因此我们在调用的时候需要传入一个整形。
fmt.Println(sum(100))
} #以上代码执行结果如下:
120
200
2>.闭包函数挖坑(你会发现该函数存取的值总是最后一位的。)
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" func main() {
var list []func()
for i :=0;i < 3 ; i++ {
list = append(list, func() {
fmt.Println(i)
//fmt.Println(&i)
})
}
for _,f := range list{
f()
}
} #以上代码执行结果如下:
3
3
3
3>.闭包函数填坑
/*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" func main() {
var list []func()
for i :=0;i < 3 ; i++ {
i := i //给i变量重新赋值,
list = append(list, func() {
fmt.Println(i)
//fmt.Println(&i)
})
}
for _,f := range list{
f()
}
} #以上代码执行结果如下:
0
1
2
九.常用内置函数介绍
未完待续。。。。
Golang面向过程编程-函数的更多相关文章
- Python开发基础-Day10生成器表达式形式、面向过程编程、内置函数部分
生成器表达式形式 直接上代码 # yield的表达式形式 def foo(): print('starting') while True: x=yield #默认返回为空,实际上为x=yield No ...
- python基础之生成器表达式形式、面向过程编程、内置函数部分
生成器表达式形式 直接上代码 1 # yield的表达式形式 2 def foo(): 3 print('starting') 4 while True: 5 x=yield #默认返回为空,实际上为 ...
- 1.面向过程编程 2.面向对象编程 3.类和对象 4.python 创建类和对象 如何使用对象 5.属性的查找顺序 6.初始化函数 7.绑定方法 与非绑定方法
1.面向过程编程 面向过程:一种编程思想在编写代码时 要时刻想着过程这个两个字过程指的是什么? 解决问题的步骤 流程,即第一步干什么 第二步干什么,其目的是将一个复杂的问题,拆分为若干的小的问题,按照 ...
- Day4 闭包、装饰器decorator、迭代器与生成器、面向过程编程、三元表达式、列表解析与生成器表达式、序列化与反序列化
一.装饰器 一.装饰器的知识储备 1.可变长参数 :*args和**kwargs def index(name,age): print(name,age) def wrapper(*args,**k ...
- Python基础(协程函数、内置函数、递归、模块和包)-day05
写在前面 上课第五天,打卡: 凭着爱,再回首: 一.协程函数(生成器:yield的表达式形式) 1.yield 的语句形式: yield 1 - 这种方式在 Python基础(函数部分)-day04 ...
- 《Essential C++》读书笔记 之 面向过程编程风格
<Essential C++>读书笔记 之 面向过程编程风格 2014-06-18 2.2 调用(invoking)一个函数 2.2.1 Pass by Reference语义 在函数sw ...
- python协程函数、递归、匿名函数与内置函数使用、模块与包
目录: 协程函数(yield生成器用法二) 面向过程编程 递归 匿名函数与内置函数的使用 模块 包 常用标准模块之re(正则表达式) 一.协程函数(yield生成器用法二) 1.生成器的语句形式 a. ...
- python基础之协程函数、列表表达式、生成器表达式
一.协程函数 协程函数的定义?如果在一个函数内部yield的使用方式是表达式形式的话,如x=yield,那么该函数称为协程函数 协程函数补充: def init(func): def wrapper( ...
- 面向过程编程(OPP) 和面向对象编程(OOP)的关系
面向过程编程(OPP) 和面向对象编程(OOP)的关系 原文链接:http://blog.csdn.net/phphot/article/details/3985480 关于面向过程的编程(OPP)和 ...
随机推荐
- WIFI探针技术
1.WIFI 探针定义 WIFI 探针是一种能够主动识别 Android 和 IOS 设备,感知用户行为轨迹的精准数据收集前端,基于 WIFI探测技术.移动互联网和云计算等先进技术自动识别探针附近的智 ...
- QT QProgressBar QProgressDialog 模态,位置设置,无边框,进度条样式
一 关于模态设置 QProgressDialog可以设置模态(需要在new的时候传入parent),QProgressBar设置不好: 只有dialog可以设置模态,widget不能设置模态(QPr ...
- opencv学习笔记(五)
线性滤波 方框滤波--boxblur函数 均值滤波(邻域平均滤波)--blur函数 高斯滤波--GaussianBlur函数 中值滤波--medianBlur函数 双边滤波--bilateralFil ...
- SpringMVC一例 是否需要重定向
在ASP.NET MVC下: return view("List") 和 return RedirectToAction("List") 百度知道的最佳答案: ...
- [转帖]台积电近10万片晶圆报废,但7nm工艺将成2019营收主力
台积电近10万片晶圆报废,但7nm工艺将成2019营收主力 2019年02月18日 13:19 1784 次阅读 稿源:Expreview超能网 0 条评论 https://www.cnbeta.co ...
- Windows查看端口被什么进程占用的简单方法----菜鸟养成
1. 还是因为同事告知Oracle的服务器连不上 最后发现改了端口就可以了, 但是很困惑 不知道为什么会这样,然后简单查了下: 命令 netstat -ano 查看监听的端口 baidu出来一个管道 ...
- Java MD5Util
package util; import java.security.MessageDigest; public class MD5Util { public static String strin ...
- 洛谷P3588 [POI2015]PUS
题面 sol:说了是线段树优化建图的模板... 就是把一整个区间的点连到一个点上,然后用那个点来连需要连一整个区间的点就可以了,就把边的条数优化成n*log(n)了 #include <queu ...
- python基础成长之路四-基础数据类型方法
1,程序开发三大流程: 顺序--从上向下,顺序执行代码 分支--根据条件判断,决定执行代码的分支 循环--让特定的代码重复执行 2,whlie循环语句: Break 某一条件满足时,退出循环,不在执行 ...
- 概率dp总结 正在更新
借bin神一句话 概率DP主要用于求解期望.概率等题目. 转移方程有时候比较灵活. 一般求概率是正推,求期望是逆推.通过题目可以体会到这点. 先推公式 多个 -> 一个 明确dp[i]代表什么意 ...