Golang基础之函数

时间:2022-09-03 13:33:37

golang基础之函数

1、为什么需要函数?

有些相同的代码可能出现多次,如果不进行封装,那么多次写入到程序中,会造成程序冗余,并且可读性降低

2、什么是函数

为完成某些特定功能的程序指令集合称为函数

3、函数分类

内建函数

自定义函数

4、函数的基本用法

基本语法

  func  函数名(形参列表) (返回值列表) {

    //执行语句

  return 返回值列表

  形参列表

    表示函数的输入

  执行语句

    表示函数执行的某功能代码

  返回值列表

    函数可以有返回值也可以没有返回值,可以返回多个,也可以一个也不返回

  使用注意

    golang中的函数可以返回多个值,如果需要返回多个值,需要在自定义函数时,声明的返回值列表必须是多个,否则报错

  案例演示

package main

import (

“fmt”

)

func main(){

key := 12

var a int = 9

if key >= 10 {

k,b := test(a)   //调用函数

fmt.Println(k,b)

fmt.Printf("%T",k)

}

}

func test(a int) (float32, int){    //声明函数

var t int  = 3

b  := float32(a + t)

c  := a + t

return b,c

}

运行结果:

12 12

float32

5、函数参数的传递方式

  基本介绍

    函数参数传递分为值传递和引用传递

  分类

    值传递

      基本数据类型、数组和结构体等都是值类型,值类型采用的是值传递

    引用传递

      指针、slice切片、map、管道chan、接口等都是引用类型,引用类型采用的是引用传递

  使用说明

    其实不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是值传递是值的拷贝,引用传递的是地址的拷贝,一般来说,地址的拷贝效率比较高,因数据量小,而值拷贝拷贝的效率取决于数据的大小,数据越大,效率越低

6、变量作用域

  基本介绍

    函数内部声明或者定义的变量叫做局部变量,作用域仅限于函数内部

    函数外部声明的或者定义的变量叫做全局变量,作用域在整个包都有效,全局变量如果在整个程序有效的前提是首字母必须大写

  注意事项

    如果变量被定义在一个代码块中,比如if或者for循环中,那么这个变量的作用域就在该代码块中

    变量的赋值不能再全局作用域进行,否则会报错。全局作用域只能声明一些变量或者函数,不能进行赋值操作

  案例演示

package main

import (

"fmt"

"strings"

)

var name int

name = 123  //错误的做法

name1 := 123  //错误的做法

func main(){

fmt.Print(name)

}

案例演示

package main

import “fmt”

name := “zhangsan”

func test(){

fmt.Print(name)  //zhangsan

}

func test1(){

name := “wangwu”

fmt.Print(name)  //wangwu

}

func main(){

test()

test1()

}

运行结果

shangsan

wangwu

7、函数使用的注意事项和细节讨论

  (1) 函数的形参列表可以是多个,返回值列表也可以是多个,返回值列表,每个值用逗号隔开

  (2) 形参列表和返回值列表的数据类型可以是值类型和引用类型

  (3) 函数命名规范遵守变量命名规范,不能以数字开头,或者包含特殊字符,首字母大写,被其他包导入时,具有可访问性。如果是小写只能被本包使用

  (4) 变量分为全局变量和局部变量,全局变量是声明在main函数中,局部变量可以声明在任何一个块结构中,比如if语句中,循环体中,自定义函数中等

  (5) 基本数据类型的和数组在传递时默认都是值传递,即进行值的拷贝,在函数内部修改,不会影响原值

  (6) 如果希望函数内部的变量修改函数外的变量,可以传入变量的地址&,函数内部已指针的方式操作变量,从效果看类似引用

  案例演示

package main

import “fmt”

func  test(n  *int){

*n = *n + 1

fmt.Print(*n)

}

func  main(){

num := 123

test(&num)

fmt.Print(num)

}

  (7) go语言不支持传统的重载(也就是通过参数列表的不同来实现的重载),go语言是用另一种方式实现的重载,而不是通过参数列表的不同来实现重载

  (8) 在Go中,函数也是一个数据类型,可以赋值给一个变量,则该变量就是函数类型的变量,通过该变量可以对函数调用

    举例说明  

package main

import “fmt”

func main(){

a := yanshi

a()    //通过把函数赋值给一个变量,变量加个括号来调用函数

fmt.Printf("%T %T",a,yanshi)

}

func yanshi(n int){

fmt.Print("案例演示")

}

  (9) 函数既然是一种数据类型,因此Go中,函数可以作为参数传递给另一个函数

    举例说明

    

package main

import “fmt”

func main(){

a := myfunc(yanshi,12)

fmt.Printf("%T %T \n",a,myfunc)

fmt.Println(a)

}

func  myfunc(funcvar  func(int) int ,num int) {   //函数作为参数时,必须把函数的参数列表和函数的返回值类型的列表补全

return funcvar(num)

}

func yanshi(n int){

fmt.Print("案例演示")

}

  (10) 函数作为参数传递时,必须把函数的声明和返回值的类型列表写全

  (11) 为了简化数据类型的定义,Go支持自定义数据类型

    基本语法

      type  自定义数据类型名  数据类型

    演示自定义数据类型

      第一个演示:   type  myint  int //相当于给int数据类型取了别名,但是这两个是独立,是不同的数据类型

      第二个演示:   type  mysum  func(int,int) int

    关于自定义类型后与原类型的问题

    使用注意

      关于子自定义函数类型作用,能够简化函数类型作为形参的定义,但是自定义函数类型的定义必须在使用这个自定义函数类型的前面

    举例说明

      不使用自定义函数 

func  myfunc(funcvar  func(int,int) int ,num int) int {   //没有使用自定义函数类型时,函数类型作为形参在参数列表时需要写很长

return funcvar(num)

}

    使用自定义函数类型

    

type  myfunctype  func(int,int) int

func  myfunc(funcvar  myfunctype ,num int) int {  //自定义函数类型后,函数作为形参,在参数列表不用写很长

return funcvar(num)

}

  (12) Go语言支持对函数返回值命名

    优点:不用一个一个在return中对应的写返回的值

    举例说明

    

package main

import “fmt”

func main(){

n := 12

m := 4

sum ,sub :=myfunc(n,m)

}

func  myfunc(n int , m int)(sum int,sub int) {   //把返回的值定义好

sum = n + m   //直接使用=等号赋值就行

sub = n-m

return      //返回时不用填任何返回数据,并且返回时不用担心对应关系,只需在接收时对应好就行

}

  (13) 使用_下划线标识符忽略返回值

package main

import “fmt”

func main(){

n := 12

m := 4

sum ,_:=myfunc(n,m)   //忽略返回值sub

}

func  myfunc(n int , m int)(sum int,sub int) {   

sum = n + m   

sub = n-m

return     

 }

(14) Go语言函数支持可变参数

基本语法:

func  sum(args... int) sum int {

//代码

}

func sum(n1 int,args... int) sum int {

//代码

}

    使用注意

      args其实是一个slice切片,通过args[index]可以访问到各个值,如果一个函数形参列表有可变参数,和其他参数,那么可变参数要放在最后,否则报错

    案例演示

    

package main

import “fmt”

func main(){

n := sum(3,1,2,3,4,5,6)

fmt.Println(n)

}

func sum(n int , args... int ) int {

s := 0

for i := 0 ; i < len(args) ; i++ {

if args[i] == n {

break

}

s += args[i]

}

return s

}

运行结果

3

  (15) 如果在函数的形参列表中,两个或者多个形参的数据类型一样,那么可以省略前面几个,最后写一个就行 

func  sum(n , m , b ,c int) int {

//代码

}

8、包的使用和使用原理

  包的使用原理

    包的本质其实就是创建不同的文件夹来存放程序文件

  包的相关说明

  使用注意

    导入包时,路径必须从src下的某个目录开始算,比如,src文件夹下有一个utils文件,utils文件下有一个utils.go文件,那么,在main.go中导入utils包下的utils.go的某个变量或者函数的路径是:import utils

9、使用包的注意事项

  1)在给一个文件打包时,该报对应一个文件夹。文件的包通常和文件所在的文件夹名是一直的,一般为小写

  2)当一个文件要使用其他包的函数或者变量时,需要先引入对应的包

    引包方式1:import  包名

    引包方式2:import (

      “包名1”

      “包名2”

      )

  3)package指令在文件第一行,然后接着是import导包命令

  4)在import包时,路径从计算机环境变量$GOPATH下的src目录开始算,不用带src目录,编译器会自动从src开始引入

  5)为了让其他包可以访问到本包的函数或者变量,则该函数或者变量的首字母必须大写

  6)在访问其他包的函数或者变量时,语法是:包名.函数名或者包.变量

  7)如果包名过长,Go语言支持跟包名取别名,如果取了别名,那么原来的包名就不能用

  8)在同一个包下面不能有重复的变量名,否则包重复定义

    说明:如果包取了别名,则必须使用别名来访问包中的函数或者变量

  9)如果两个.go文件打了同一个包,并且这两个文件都有同一个名字的函数或者变量,这样都会报错,因为同一个包下只能有一个函数名或者变量名,即使这个两个函数名被定义在两个不同的但是打了同一个包的文件

  10)在一个go程序中,main包只能有一个

  函数中return语句使用注意

    注意:对于函数的返回值,如果函数返回多个值,但是你只需要某个值,那么不需要的值可以使用下划线接受,例如:  _ , a := getSum(a,b)。

10、函数之递归调用

  基本介绍

    一个函数体内调用了本身,我们称为递归调用

  案例演示

func  test( a  int ) {

if   a > 2 {

a--

test(a)

}

fmt.Println(a)

}

func  main(){

test(4)

}

运行结果:

2

2

3

 执行流程

  Golang基础之函数

   使用注意

    ① 递归每执行一个函数时,就创建一个新的受保护的独立的空间,也可以说是一个新的函数栈

    ② 函数的局部变量是独立的,不会相互影响

    ③ 递归必须向退出递归的条件逼近,否则就是无限递归

    ④ 当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁。执行完毕时,或者返回时,该函数栈会被销毁

  (1) 书写递归的重要思想就是:寻找出路

11、递归之解决斐波那契数列

  (2) 比如有一个数列:1 1 2 3 5 7 12 19.......

  (3) 实现思路

    1、当数列在1和2位置时值为1

    2、数列的前一个数和后一个数相加等于第三个数

  (4) 实现代码

package main

import “fmt”

func main{

//1  1  2  3  5 ....

n := 0

fmt.Print("请输入你要查找的数:")

fmt.Scanln(&n)

a := fibonaqi(n)

fmt.Println(a)

}

  //求斐波那契第n个位置的值

func  fibonaqi(n int) int {

if  n == 1 || n == 2 {

return 1

}

return fibonaqi(n-1)+fibonaqi(n-2)

}

运行结果:

Golang基础之函数

12、求函数值

   已知f(1)=3,f(n)=2*f(n-1)+1,请使用递归求出n为任意数的值

  解题思路

    寻找递归出口,这里是f(1)=3

  实现代码

package main

import “fmt”

func main{

//1  1  2  3  5 ....

n := 0

fmt.Print("请输入你要查找的数:")

fmt.Scanln(&n)

a := hs(n)

fmt.Println(a)

}

func hs( n int) int {

if n == 1 {

return 3

}

return 2 * hs(n-1) + 1

}

13、递归练习之猴子吃桃子

  问题描述

Golang基础之函数

  问题解剖

    1、当到10天时,只剩下一个

    2、前一天的个数为后一天个数加1乘以2

  实现代码

package main

import “fmt”

func main{

//1  1  2  3  5 ....

n := 0

fmt.Print("请输入你要查找的数:")

fmt.Scanln(&n)

a := chi(n)

fmt.Println(a)

}

func chi(d int ) int {

//设第d天还剩下n个

if d == 10  {

return 1

} else if d > 10 {

return 1

}

return ( chi(d + 1) + 1 ) * 2

}

运行结果:

Golang基础之函数

14、Go语言中的init函数

  基本介绍

    每个源文件中都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用,也就是说init会在main函数执行前执行

  案例演示

  

package main

import "fmt"

func init(){

fmt.Println("我先被执行了?")

}

func main(){

fmt.Println("我后被执行?")

}

打印:

PS F:\goProjects\src\test> go run .\utils.go

我先被执行了?

我后被执行?

init函数的使用细节

  如果一个文件中同时包含全局变量定义init函数main函数,则执行先后流程是:先执行全局变量定义---->init函数------>main函数最后执行

  案例演示

  

package main

import "fmt"

var num = test()

func test() int {

fmt.Print(“我最先被执行?”)

return 100

}

func init(){

fmt.Println("")

}

func main(){

fmt.Printf("我最后被执行?%d",num)

}

运行结果:

我最先被执行?

我第二个被执行了?

我最后被执行?100

  使用注意

    如果一包里边包含一个init函数,当我们把这个包导入main.go文件中,当执行main.go时,先执行导入包中的init函数,为什么呢?因为程序运行时,代码从上往下开始执行,当执行到导入包时,如果导入的包有init函数,就会去执行导入包的init函数

15、Go语言的匿名函数

  基本介绍

    Go语言支持匿名函数,如果某个函数只希望被使用一次,可以考虑使用匿名函数。匿名函数也可以实现多次调用

  匿名函数的使用

    方式1:将匿名函数赋值给一个变量(函数变量),在通过该变量来来调用匿名函数

  

案例演示

package main

import "fmt"

func main(){

//求两个数的和,使用匿名函数来完成

functions  :=  func ( n1 ,n2 int ) int {  

return n1 + n2

}  

sum := functions(10,20)  //可以通过变量多次调用匿名函数

fmt.Print(sum)

}

方式2:在定义匿名函数时就直接调用,这种方式匿名函数只能调用一次

案例演示

package main

import "fmt"

func main(){

//求两个数的和,使用匿名函数来完成

sum := func ( n1 ,n2 int ) int {  //匿名函数没有函数名,结果直接用一个变量接受

return n1 + n2

}(10,20)  //调用

fmt.Print(sum)

}

  全局匿名函数

    基本介绍

      如果将匿名函数赋值一个全局变量,那么这个匿名函数就称为全局匿名函数,可以在程序中有效

    案例演示

  

package main

import "fmt"

var (

Fun1 = func (n , m int ) int {

return n + m

}  //全局匿名函数的定义

)

var  func2 = func (n int ) int {

return 1

}  //这样定以也是可以

func main(){

sum := Fun1(1,2)

fmt.Print(sum)

}

  16、defer

    基本介绍

      延迟执行某些代码

    使用案例

package main

import (

"fmt"

"strings"

)

func sum(n , m int ) {

defer fmt.Println(n)

defer fmt.Println(m)

n = n+m

fmt.Println(n)

}

func main(){

sum(1,2)

fmt.Println(“执行”)

}

  使用注意

    当编译器执行到defer语句时,不会马上执行defer后边的语句,他会将defer后的语句压入到一个derfer栈(为理解取的名字)中。当函数执行完毕后,再冲defer栈中将原来压入站的语句拿出来执行

    defer后面的语句被压入栈中是,也会将在这个语句前定义的变量拷贝到这个defer栈中

      注意:defer栈的取名是为了理解而取的

    defer使用价值

      defer最主要的价值在于但函数执行完毕后可以及时的是仿函数创建的资源。比如:打开一个文件的句柄,释放一个数据库资源等都可以使用defer在函数调用完毕后关闭

Golang基础之函数的更多相关文章

  1. golang基础--func函数

    函数function Go函数不支持 嵌套, 重载和默认参数 支持以下特性: 无须声明原型,不定长度长度变参,多返回值,命名返回值参数,匿名函数,闭包 定义函数使用关键字func,且左侧大括号不能另起 ...

  2. GoLang基础数据类型---&gt&semi;字典(map)详解

    GoLang基础数据类型--->字典(map)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   可能大家刚刚接触Golang的小伙伴都会跟我一样,这个map是干嘛的,是 ...

  3. GoLang基础数据类型---&gt&semi;数组(array)详解

    GoLang基础数据类型--->数组(array)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Golang数组简介 数组是Go语言编程中最常用的数据结构之一.顾名 ...

  4. golang基础之工程结构

    Golang 工作空间 编译工具对源码目录有严格要求,每个工作空间 (workspace) 必须由 bin.pkg.src 三个目录组成. workspace | +--- bin // go ins ...

  5. python基础——匿名函数

    python基础——匿名函数 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便.  在Python中,对匿名函数提供了有限支持.还是以map()函数为例,计算f(x)=x2时 ...

  6. python基础——返回函数

    python基础——返回函数 函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回.  我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_ ...

  7. python基础——sorted&lpar;&rpar;函数

    python基础——sorted()函数 排序算法 排序也是在程序中经常用到的算法.无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小.如果是数字,我们可以直接比较,但如果是字符串或者两个d ...

  8. python基础——filter函数

    python基础——filter函数 Python内建的filter()函数用于过滤序列. 和map()类似,filter()也接收一个函数和一个序列.和map()不同的是,filter()把传入的函 ...

  9. golang基础知识之encoding&sol;json package

    golang基础知识之json 简介 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式.可以去json.org 查看json标准的清晰定义.json pack ...

随机推荐

  1. Unity VR全景漫游

    一.前言: 最近VR如火如茶,再不学习就落伍啦.有空闲时间,跟Rodolfo一起研究下相关知识. 本文介绍了两种方法来制作VR场景: 方法一:通过6张小图搭建的VR场景 方法二:通过一张全景图来搭建V ...

  2. 常用的正则表达式(例如:匹配中文、匹配html)(转载)

    匹配中文字符的正则表达式: [u4e00-u9fa5]    评注:匹配中文还真是个头疼的事,有了这个表达式就好办了  匹配双字节字符(包括汉字在内):[^x00-xff]  评注:可以用来计算字符串 ...

  3. Machine Learning for hackers读书笔记&lpar;八&rpar;PCA:构建股票市场指数

    library('ggplot2') prices <- read.csv('G:\\dataguru\\ML_for_Hackers\\ML_for_Hackers-master\\08-PC ...

  4. Laravel框架数据库CURD操作、连贯操作总结

    这篇文章主要介绍了Laravel框架数据库CURD操作.连贯操作.链式操作总结,本文包含大量数据库操作常用方法,需要的朋友可以参考下 一.Selects 检索表中的所有行 复制代码代码如下: $use ...

  5. Android中定时器的3种实现方法

    原文:http://blog.csdn.net/wulianghuan/article/details/8507221 在Android开发中,定时器一般有以下3种实现方法: 一.采用Handler与 ...

  6. 编写一个单独的Web Service for Delphi7&lpar;步骤&rpar;

    1新建一个SOAP Server Application,在提示输入接口时输入MyHello,把所有文件保存在一个叫Ser的目录下,其中一个包含TWebModule1的文件保存为main.pas.在M ...

  7. 第一章 初识Lucene

    多看几遍,慢就是快 1.1 应对信息爆炸 1.2 Lucene 是什么 1.2.1 Lucene 能做些什么 1.2.2 Lucene 的历史 1.3 Lucene 和搜索程序组件 基本概念 索引操作 ...

  8. mysql安装注意

    mysql安装教程,网上到处都有,我这里就不细说了. 但是有一点要注意,安装完之后,点击MySql 5.5 Command Line Client时,有可能出现一闪而过,打不开mysql的情况: 首先 ...

  9. Spark SQL UDF示例

    UDF即用户自定函数,注册之后,在sql语句中使用. 基于scala-sdk-2.10.7,Spark2.0.0. package UDF_UDAF import java.util import o ...

  10. 基于Landmark的人脸对齐以及裁剪方法

    利用Landmarks进行人脸对齐裁剪是人脸检测中重要的一个步骤.效果如下图所示: 基本思路为: a.人脸检测 人脸的检测不必多说了,基本Cascade的方式已经很不错了,或者用基于HOG/FHOG的 ...