go 函数 详解

函数的定义和使用

(1)语法:

func 函数名(形参列表)(返回值类型列表){
   //代码体(程序体)
   执行语句…
   return + 返回值列表
}

函数定义:只能定义一次,名字是唯一的。

package main
import "fmt"
//函数定义 只能定义一次 名字是唯一的
func add(s1 int, s2 int) {
   sum := s1 + s2
   fmt.Println(sum)
}
func main() {
   a := 10
   b := 20
   /* 函数的调用  函数可以多次调用
   在函数调用时参数为实际参数(实参) 有具体的值 用来给形式参数(形参) 传递数据
   */
   add(a, b)
   add(1, 2)
}

函数的调用:函数可以多次调用,在函数调用时参数为实际参数(实参) 有具体的值 用来给形式参数(形参) 传递数据。

(2)函数的作用:提高代码的复用性。
(3)函数名:
         遵循标识符命名规范:见名知意 addNum,驼峰命名addNum
         首字母不能是数字
         首字母大写该函数可以被本包文件和其它包文件使用(类似public)
         首学母小写只能被本包文件使用,其它包文件不能使用(类似private)
         函数名不能一样
(4)形参列表:
         形参列表:个数:可以是一个参数,可以是n个参数,可以是0个参数
         形式参数列表:作用:接收外来的数据
         实际参数:实际传入的数据

(5)返回值类型列表:函数的返回值对应的类型应该写在这个列表中

  • 返回0个:如果没有返回值,那么返回值类型什么都不写就可以了
  • 返回1个:如果返回值只有一个,那么这个列表中类型左右的()可以省略不写
  • 返回多个:带括号()
             如果有返回值不想接收,那么可以用_进行忽略不接受

不定参函数

...不定参,在函数调用时可以传递不定量(0-n)的参数,不定参使用数据的格式为切片。不定参不是数组,是数据的集合。

package main

import "fmt"

func main() {
	sum(1, 2, 3)
}

func sum(arr ...int) {
	/* arr是数据的集合,不是数组 */
	//fmt.Println(arr)   // [1 2 3]
	count := len(arr) //集合个数
	//fmt.Println(count) // 3
	/* 通过arr[下标]可以找到具体数据的值,小标从0开始 */
	//fmt.Println(arr[0]) // 1
	//fmt.Println(arr[1]) // 2
	/* 通过for循环遍历集合中的数据 */
	for i := 0; i < count; i++ {
		fmt.Println(arr[i])
	}
}

len(字符串) 计算字符串个数
len(数据集合) 计算数据集合的个数

如果不定参的函数调用时传递的参数为多个,不定参要写在后面。

下面演示正确和错误的写法:

  1. 正确的
func sum(a int,  arr ...int) {
}
  1. 错误的
func sum(arr ...int, a int ) {
}

函数嵌套使用

package main
import "fmt"
func test1(a, b int) {
   fmt.Println(a + b)
}
//函数参数传递时如果有多个参数  中间 用逗号分隔
//
func test(a int, b int) {
   test1(a, b)
}
func main() {
   a := 10
   b := 20
   test(a, b)
}

注意:不能将不定参的名称传递给另外一个不定参

package main
import "fmt"
func test1(arr ...int) {
	//test2(arr) //err:cannot use arr (variable of type []int) as type int in argument to test2
	//不能将不定参的名称传递给另外一个不定参
	/*下面不报错*/
	//传递指定个数的数据
	test2(arr[0:4]...) //起始0,结束4,不包含4,4之前的数据
	test2(arr[0:len(arr)]...)
}
func test2(arr ...int) {
	fmt.Println(arr)
}
func main() {
	test1(1, 2, 3, 4)
}

函数返回值

func 函数名(形参列表)(返回值类型列表){
   //代码体(程序体)
   执行语句…
   return + 返回值列表
}

(1) 单个返回值

  1. 传统写法要求:返回值和返回值的类型对应,顺序不能差。
package main
import "fmt"
func main() {
	a := 10
	b := 20
	sum := test4(a, b)
	fmt.Println(sum)
}
//func 函数名(函数参数列表)(函数返回值)
//如果一个返回值就可以不用括号
func test4(a int, b int) int {
	/* sum := a + b
	return sum */
	return a + b
}

return 表示函数的结束,如果函数有返回值return可以将返回值返回。函数会有销毁的过程,返回值返回回来并不是通过内存返回回来,而是通过CPU把这个值返回回来,a+b存在CPU的计算器中,然后再从计算器中返回的

  1. 我们还可以这种格式来写
func test4(a int, b int) (sum int) {
	sum = a + b
	return //相当于return sum
}

(2)多个返回值

  1. 升级写法:对函数返回值命名,里面顺序就无所谓了,顺序不用对应
func main() {
	//函数有多个返回值 要一一对应接收数据
	sum, sub := test5(10, 20)
	_, x := test5(1, 1)
	fmt.Println(sum, sub) //30 -10
	fmt.Println(x)        //0
	/* 加入两个变量都不想用 */
	// _, _ := test5(1, 1)//err:必须得有一个接收
	test5(1, 1) //我们可以这样不接受,不会报错
}
//1
func test5(a int, b int) (sum int, sub int) {
	sum = a + b
	sub = a - b
	return
}

test5可以换一种写法

//2
func test5(a int, b int) (int, int) {
	sum := a + b
	sub := a - b
	return sum, sub
}

函数类型

函数的名字表示一个地址,函数在代码区的地址

package main
import "fmt"
func demo(a int, b int) {
   fmt.Println(a + b)
}
func main() {
   demo(10, 20)
   fmt.Println(demo) //0x2cb460  默认打印的是一个代码区的地址
   //f是func(int, int)函数类型定义的变量
   //f := demo
   var f func(int, int)
   f = demo

   fmt.Println(f) //0x2cb460  代码区的内存地址
   //通过f调用函数
   f(10, 20)
   fmt.Printf("%T", f) //func(int, int)  
}

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

func demo(a int, b int) {
	fmt.Println(a + b)
}
func demo2(x int, y int) {
	fmt.Println(x - y)
}
func main() {
	//f := demo
	var f func(int, int)
	f = demo
	f = demo2//不报错
	f(1, 2)

}

注意:当定义好函数类型的时候格式就确定了,如果是新的格式就不行

package main

import "fmt"

//func(int, int)
func demo(a int, b int) {
	fmt.Println(a + b)
}

//func(int, int) int
func demo2(x int, y int) int {
	return x + y
}
func main() {
	//f := demo
	var f func(int, int)
	f = demo
	f = demo2 //err报错
	fmt.Printf("%T", f)
}

为了简化数据类型定义,Go支持自定义数据类型

基本语法: type 自定义数据类型名 数据类型

可以理解为 : 相当于起了一个别名。如果我们在很多程序中定义这样的格式,取别名在使用可以更方便一点。

package main

import "fmt"

//func(int, int)
func demo(a int, b int) {
	fmt.Println(a + b)
}

//func(int, int) int
func demo2(x int, y int) int {
	return x + y
}

//定义函数类型 为已存在的数据类型起别名
type FUNCDEMO func(int, int)

func main() {
	var f FUNCDEMO
	f = demo
	fmt.Printf("%T", f)//main.FUNCDEMO
}

函数既然是一种数据类型,因此在Go中,函数可以作为形参,并且调用(把函数本身当做一种数据类型)

package main
import "fmt"
//定义一个函数:
func test(num int){
        fmt.Println(num)
}
//定义一个函数,把另一个函数作为形参:
func test02 (num1 int ,num2 float32, testFunc func(int)){
        fmt.Println("-----test02")
}
func main(){
        //函数也是一种数据类型,可以赋值给一个变量	
        a := test//变量就是一个函数类型的变量
        fmt.Printf("a的类型是:%T,test函数的类型是:%T \n",a,test)//a的类型是:func(int),test函数的类型是:func(int)
        //通过该变量可以对函数调用
        a(10) //等价于  test(10)
        //调用test02函数:
        test02(10,3.19,test)
        test02(10,3.19,a)
}

函数的作用域

局部变量

变量先定义后使用,在函数内部变量名是唯一的。在函数定义的变量称为 局部变量,局部变量的作用域在函数内部。

for也是独立的模块,for的i与外面的i不冲突的,不会影响到外面的i

package main
import "fmt"
func main() {
	a := 10
	fmt.Println(a)
	
	var i int = 10 //不会报错
	for i := 0; i < 5; i++ {
		fmt.Println(i) //0 1 2 3 4
	}
	fmt.Println(i) //10
}

全局变量

在函数外部定义的变量称为 全局变量,作用域是在项目中整个文件去使用,定义的全局变量名不能和其他文件中的变量名重名。全局变量名可以和局部变量名重名。当全局变量一个值改变之后,会影响项目整个的数值。

在go语言中会采用就近原则,如果在函数内部定义的局部变量和全局变量重名,会使用局部变量。

全局变量名字是唯一的不能和其他全局变量重名,但是可以和局部变量重名。

问:全局作用域范围大还是局部作用域范围大?
答:很难确定,因为在某些不同的场合,你也不能说谁作用范围大、先使用谁后使用谁的问题,一定要看具体的语法。

package main
import "fmt"
var a int = 666
func main() {
	fmt.Println(a) //666
	a = 11
	fmt.Println(a) //11
	test6()        //11
	//全局变量名可以和局部变量名重名
	a := 10
	a = 999
	//就近原则	
fmt.Println(a) //打印的局部变量999
}
func test6() {
	fmt.Println("test6:", a)
}

全局变量存储在内存的数据区,如果全局变量定义时有值 存储在初始化数据区 ,没有值存储在未初始化数据区。

package main

import "fmt"

var a int = 666

func main() {
	//打印代码区的地址 	代码区
	fmt.Println(test6)
	//打印全局变量的地址   数据区
	fmt.Println(&a) //0xbe3338
	a := 11
	//打印局部变量的地址	栈区
	fmt.Println(&a) //0xc00000a0d0
}
func test6() {
	fmt.Println("test6:", a)
}

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值