Golang入门笔记(7)—— 函数 func
创始人
2024-01-28 13:42:20

       函数是什么? 函数:为完成某一功能的程序的语句指令的集合。

   

感觉重头戏逐渐到来了,让我们好好的,认真对待它吧!

 

        为什么要使用函数? 为了提高代码的复用,减少代码的冗余,提高代码维护性——避免每次都编码一段类似代码。

        基本语法:

func functionName(形参列表...)(返回值的类型列表){执行语句...return + 返回值列表
}

         其中,如果返回值类型是一个,可省略第二个小括弧,代码如下:

package mainimport "fmt"func main() {sum := calculate(10, 20) //实参。fmt.Println(sum)
}func calculate(num1 int, num2 int) int { //形参sum := 0sum += num1sum += num2return sum
}

        注意事项:       

  •          函数名:

1.遵循标识符命名规范——驼峰命名法,要能见名知意。

2.首字符不能是数字。

3.如果首字母大写该函数可以被本包文件和其他包文件使用;如果首字母小写只能被本包文件使用,其他包不能使用。

4. Go语言中,函数不支持重载。所以同一block中,函数名不可重复声明,否则会 报 redecleared in this block 的错误。

  •         形参列表:

1. 用于接收外部传入的参数,其参数的个数,可以0个,也可以是n个。

2.支持可变参数,即函数参数的数量可根据实际情况弹性伸缩 。(ps 后面等熟悉了函数后,末尾会专门介绍)

  •         返回值列表:

返回值类型列表:

        1.可以返回0个数据类型,可以返回n个数据类型。

返回0个数据类型

func main() {calculate(10, 20)
}//函数定义中无返回值类型列表
func calculate(num1 int, num2 int)  {sum := 0sum += num1sum += num2fmt.Println(sum)
}

返回n个数据类型

package mainfunc main() {//需要2个变量接受此函数返回的多个类型的数据r1, r2 := calculate(10, 20)println(r1, r2)
}//返回多个数据类型的函数
func calculate(num1 int, num2 int) (int, int) {sum := 0sum += num1sum += num2var result int = num1 - num2return sum, result
}

        2. 对于不关注的返回,可以使用_忽略。比如:

//可以用 下划线 ,忽略不关注的返回值。r1, _ := calculate(10, 20)println(r1)

函数执行内存分析:

        先看一段代码:思考执行结果为什么会这样?

package mainimport "fmt"func main() {num1 := 10num2 := 20exchange(num1, num2)fmt.Printf("num1 = %v , num2 = %v", num1, num2) //num1 = 10,num2 = 20
}func exchange(num1 int, num2 int) {var t intt = num1num1 = num2num2 = t
}

        知识预热:

        栈区:用来存储程序执行过程中函数内部定义的信息和局部变量值。 最内层函数后进先出,最内层函数先执行后,释放内存,向上层传递结果。 函数return返回值将函数执行的结果保存下来,返回给调用者。

        上面这个函数,在内存中的函数执行过程,如下图所示:

当exchange执行完毕之后,出栈 销毁函数栈帧(栈空间)——上面exchage栈空间就会出栈而消失

                   以上函数的内存活动的主要发生在逻辑栈上,根据如上图的内存分析就可得出问题所在。

可变参数案例:

        相信在这里,大家已经大致了解了函数了,这里 详细看一下 可变参数的案例。

package mainfunc main() {res := calculate("*", 1, 2, 3, 4)println(res)
}func calculate(op string, num ...int) int {res := 1if "*" == op {for i := 0; i < len(num); i++ {res *= num[i]}}return res
}

       注意:可变参数,要是必须是最后一个参数,这是一个通用的语言语法规范,js-ecmascript6版本 和 java 也都是如此。

  •         函数的参数的传递方式:

        基本数据类型和数组默认都是值传递,即进行值得拷贝,在函数内修改,不会影响到原来的值。

package mainimport "fmt"func main() {num := 1changeValue(num)println(num)
}func changeValue(num int) {num = 1000fmt.Println(" changeValuetest num  --> ", num)
}

       此种情况为什么会出现这样的结果,大概的原理和上面的内存分析模型几乎差不多的。       

         对于以值传递方式的数据类型,如果希望在函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量。从效果上看类似 引用传递。

package mainimport "fmt"func main() {num := 1println("num地址", &num)changeValue(&num) //调用函数的时候,传入num的地址。println(num)
}func changeValue(num *int) { // 定义了一个int类型的指针//用*访问到这个地址的内存。*num = 1000fmt.Println(" changeValuetest num  --> ", num)
}

以上代码的内存分析图:

传入 *int变量地址 的方式

Go函数也是一种数据类型
        这点和javascript一样,可以赋值给一个变量,则该变量就是一个函数类型的变量,通过该变量可以调用该函数。正式由于函数是一个数据类型的特性,在Go的世界中,函数可以作为形参传递并且调用。这不禁让我想到Javascript 的cb()函数的使用,以及 java 通过抽象一个接口,做一个匿名内部类等方式有得一拼。

package mainimport "fmt"func main() {a := sayfmt.Printf("a 得类型是 %T,say 函数得类型是 %T \n", a, say)a("your")say("my")
}func say(whose string) {println("this is " + whose + "callback, just test this feature. ")
}

        根据这种特性,编写回调函数。

package mainfunc main() {a := calculatevar res int = test(a, 1, 2, 3, 4, 5)println(res)
}func calculate(op string, num ...int) int {res := 1if "*" == op {for i := 0; i < len(num); i++ {res *= num[i]}}return res
}func test(cb func(string, ...int) int, nums ...int) int {return cb("*", nums...) // 根据javascript 的 rest 的语法,瞎试的竟然也成了。
}

        编写以上代码的心得体会:

* func 函数当参数传递的时候,细节点,要传入定义好的参数类型和返回值类型。 

* 当遇到可变参数的时候,如这里的 num...  , 可变参数的代表变量要和三个点 在一起打包传递,这样来声明这个是一组可变的参数值。

自定义数据类型(给数据类型别名):

package mainimport "fmt"func main() {//自定义数据类型,给类型起了别名。type myInt intvar num1 myInt = 30fmt.Println("num1", num1)var a int = 20//a = num1 // cannot use num1 (variable of type myInt) as type int in assignmenta = int(num1) // 别名通过 int() 进行强转为原来的类型。println(a)
}

自定义函数类型

// 优化前
func test(cb func(string, ...int) int, nums ...int) int {return cb("*", nums...) // 根据javascript 的 rest 的语法,瞎试的竟然也成了。
}//优化后,使用 自定义的函数类型,使得代码更加简洁
type operateFunction func(string, ...int) intfunc test(cb operateFunction, nums ...int) int {return cb("*", nums...) // 根据javascript 的 rest 的语法,瞎试的竟然也成了。
}

支持函数返回值的命名操作:

package mainfunc main() {}// 返回值的列表顺序必须要和返回值的类型,一一对于,不可弄乱。
func test01(num1 int, num2 int) (int, int) {sum := num1 + num2sub := num1 - num2return sum, sub
}// 通过返回列表声明的变量 字符 ,可以进行映射。可以不用管顺序,减少编码错误。
func test02(num1 int, num2 int) (sub int, sum int) {sum = num1 + num2sub = num1 - num2return
}

        细节好多,多多练习。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
不用电脑怎么设置苹果铃声 ip... 需要一个app,加上苹果自带的app即可1、手机下载爱思极速版。因为之前换手机搬移数据时店员帮忙整理...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
才高八斗的主人公 三顾茅庐的主... 古代君王在建立自己的政治体系之时,大多会采取一些礼贤下士的手段,对于一些有卓越才能的人放低姿态。因为...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...