作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.函数的引入
1.为什么要使用函数
函数的作用就是提高代码的复用,减少代码的冗余,代码的维护性也提高了。
为完成某一功能的程序指令(语句)的集合,称为函数。
2.函数使用的细节
- 1.函数是对特定的功能进行提取,形成一个代码块,这个代码块就是我们所说的函数;
- 2.函数的作用就是提高代码的复用性;
- 3.函数和函数是并列的关系,所以我们定义的函数不能写到main函数中;
- 4.Golang中函数不支持重载(所谓重载就是函数名相同,形参列表不同的情况,Java语言支持重载),如果你强行定义则会报错重复定义;
- 5.Go语言支持对函数返回值命名;
- 6.Golang中支持可变参数,如果你希望函数带有可变的参数;
- 7.基本数据类型和数组默认都是值传递的,即进行值拷贝,在函数内修改,不会影响到原来的值;
- 8.以值传递的数据类型,如果希望在函数内的变量能修改函数外的变量,可以传入变量的指针地址("&"),函数内以指针的方式操作变量,从效果来看类似引用传递;
- 9.在Go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量了,通过该变量可以对函数调用;
- 10.函数既然是一种数据类型,因此在Go中,函数可以作为形参(把函数本身当做一种数据类型),并且调用;
- 11.为了简化数据类型定义,Go支持此自定义数据类型,比如"type 字典变异数据类型名称 数据类型",可以理解为"起别名";
- 12.当我们的一个函数返回值类型为slice时,nil可以看做是一个有效的slice,没必要显示返回一个长度为0的切片;
3.定义函数语法
Go语言中定义函数使用func关键字,具体格式如下:
func 函数名(形参列表)(返回值类型列表){
函数体代码块
return + 返回值列表
}
相关参数说明如下:
函数名:
- 1.遵循标识符命名规范,由字母、数字、下划线组成。但函数名的第一个字母不能是数字;
- 2.在同一个包内,函数名也称不能重名(包的概念后续讲解会陆续分享哟~);
- 3.首字母大写函数可以被本报文件和其他包文件使用(类似JAVA语言的public关键字);
- 4.首字母小写只能被本报文件使用,其他包文件不能被使用(类似JAVA语言的private关键字);
形参列表:
- 1.参数由参数变量和参数变量的类型组成,多个参数之间使用","分隔;
- 2.形参列表的个数是根据你功能需要设定的,可以不指定形参列表,也可以定义多个形参;
- 3.形参列表(简称"形参")的作用就是用来接收外来的数据;
- 4.实际参数(简称:"实参")是实际传入函数的数据;
返回值类型列表:
- 1.返回值由返回值变量和其变量类型组成,也可以只写返回值的类型。
- 2.多个返回值必须用"()"包裹,并用","分隔。
- 3.返回值个数是根据你功能需要设定的,可以不指定返回值,也可以定义多个返回值;
函数体:
实现指定功能的代码块。
二.定义函数案例
1.不返回任何参数
package main
import "fmt"
// 自定义函数功能: 实现两个数相加的和
// - 1.函数的参数中如果相邻变量的类型相同,则可以省略类型,这两个参数的类型均为int,因此可以省略m的类型,因为n后面有类型说明,m参数也是该类型。
// - 2.定义的函数可以没有返回值哟
func calculateSum(m, n int) {
sum := m + n
fmt.Printf("%d + %d = %d\n", m, n, sum)
}
func main() {
// // 功能1: 100 + 200
// var (
// a int = 100
// b = 200
// sum = 0
// )
// // sum += a
// // sum += b
// sum = calculateSum(a,b)
// fmt.Printf("%d + %d = %d\n", a, b, sum)
// // 功能2: 300 + 400
// var (
// x int = 300
// y = 400
// sum2 = 0
// )
// sum2 += x
// sum2 += y
// fmt.Printf("%d + %d = %d\n", x, y, sum2)
// 使用函数功能,就可以将上面需要重复写的代码功能提取出来,方便以后多次调用了,提高了代码的冗余性
var (
a int = 100
b = 200
x = 300
y = 400
)
// 调用函数
calculateSum(a, b)
calculateSum(x, y)
}
2.返回一个参数
package main
import "fmt"
// 自定义函数功能: 实现两个数相加的和
// - 1.函数的参数中如果相邻变量的类型相同,则可以省略类型,这两个参数的类型均为int,因此可以省略m的类型,因为n后面有类型说明,m参数也是该类型。
// - 2.如果返回值类型就一个的话,那么"()"是可以省略不写的哟;
func calculateSum(m, n int) int {
return m + n
}
func main() {
var (
a int = 500
b = 600
x = 700
y = 800
)
// 调用函数
sum1 := calculateSum(a, b)
sum2 := calculateSum(x, y)
fmt.Printf("%d + %d = %d\n", a, b, sum1)
fmt.Printf("%d + %d = %d\n", x, y, sum2)
}
3.返回多个参数
package main
import "fmt"
// 自定义函数功能: 实现两个数的"和","差"。
// - 1.函数的参数中如果相邻变量的类型相同,则可以省略类型,这两个参数的类型均为int,因此可以省略m的类型,因为n后面有类型说明,m参数也是该类型。
// - 2.如果返回值类型有多个的话,那么"()"是不可以省略的;
func calculate(m, n int) (int, int) {
return m + n, m - n
}
func main() {
var (
a int = 500
b = 600
x = 800
y = 900
)
// 调用函数
sum, sub := calculate(a, b)
fmt.Printf("%d + %d = %d\n%d - %d = %d\n", a, b, sum, a, b, sub)
// 如果有返回值不想接收,那么可以使用"_"进行忽略,
sum2, _ := calculate(x, y)
fmt.Printf("%d + %d = %d\n", x, y, sum2)
}
4.返回值命名
package main
import (
"fmt"
)
// 函数定义时可以给返回值命名,并在函数体中直接使用这些变量,最后通过return关键字返回。
func calculate(x, y int) (sum, sub int) {
fmt.Println("in calculate ... 返回值命名")
sub = x - y
sum = x + y
// 注意,此处无需写返回的对象,因为默认会返回sum和sub变量哟~顺序是固定的
return
}
func calculate2(x, y int) (int, int) {
fmt.Println("in calculate2 ...")
sub := x - y
sum := x + y
// 定义要返回的顺序,至于需要第一个参数先返回sub还是sum可以由你来定义
return sub, sum
}
func main() {
var (
a int = 100
b int = 20
)
result01, result02 := calculate(a, b)
fmt.Printf("%d + %d = %d\n", a, b, result01)
fmt.Printf("%d - %d = %d\n", a, b, result02)
result03, result04 := calculate2(a, b)
fmt.Printf("%d + %d = %d\n", a, b, result04)
fmt.Printf("%d - %d = %d\n", a, b, result03)
}
5.可变参数
package main
import (
"fmt"
)
// 1.可变参数是指函数的参数数量不固定,Go语言中的可变参数通过在参数名后加“...”来标识。
// 2.可变参数通常要作为函数形参的最后一个参数。
func calculate(operator string, args ...int) int {
sum := 0
mul := 1
if operator == "+" {
for _, v := range args {
sum += v
}
return sum
} else if operator == "*" {
for _, v := range args {
mul *= v
}
return mul
} else {
return -1
}
}
func main() {
var (
a int = 10
b = 20
c = 30
d = 40
)
sum := calculate("+", a, b, c, d)
mul := calculate("*", a, b, c)
fmt.Printf("sum = %d\n", sum)
fmt.Printf("mul = %d\n", mul)
}
三.函数使用细节
1.函数默认以值传递
package main
import "fmt"
func swapNumber(a, b int) {
var temp int
temp = a
a = b
b = temp
}
func main() {
var (
x int = 100
y = 200
)
fmt.Printf("交换前的两个数: x = [%d], y = [%d]\n", x, y)
swapNumber(x, y)
fmt.Printf("交换后的两个数: x = [%d], y = [%d]\n", x, y)
}
2.函数实现指针传递
package main
import "fmt"
// 参数的类型为指针
func updateValue(number *int) {
// 对指针地址对应的变量进行修改
*number = 200
}
func main() {
var x int = 100
fmt.Printf("x的地址为:%v, x = [%d]\n", &x, x)
// 注意,此处我们传递的是变量的地址哟
updateValue(&x)
fmt.Printf("x的地址为:%v, x = [%d]\n", &x, x)
}
3.函数作为变量
package main
import "fmt"
func xixi(number int) {
fmt.Printf("in xixi ...,您传递的数字为: [%d]\n", number)
}
func main() {
// 在Go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量了,通过该变量可以对函数调用;
haha := xixi
fmt.Printf("xixi的类型是: [%T],haha的类型是: [%T]\n", xixi, haha)
// 调用haha等同于调用"xixi(100)"
haha(100)
}
4.函数作为形参
package main
import "fmt"
func xixi(number int) {
fmt.Println("in xixi函数")
}
// 定义一个函数,把另一个函数作为形参传递
func haha(a int, b float64, testFunc func(int)) {
fmt.Println("in hehe函数")
}
func main() {
// 定义一个xixi函数的变量,其函数签名为: "func(int)"
heihei := xixi
// 调用haha函数
haha(100, 3.14, xixi)
haha(200, 9.18, heihei)
}
5.自定义数据类型
package main
import "fmt"
func xixi(number int) {
fmt.Println("in xixi函数")
}
// 我们可以给函数起别名
type myFunc func(int)
// 定义一个函数,把另一个函数作为形参传递
func haha(a int, b float64, testFunc myFunc) {
fmt.Println("in hehe函数")
}
func main() {
// 为了简化数据类型定义,Go支持此自定义数据类型,此处是给int类型齐了个别名叫myInt类型
type myInt int
var a myInt = 100
var b int = 200
// myInt类型虽然是int类型的别名,但是在Go中编译识别的时候还是认为myInt和int不是一种数据类型。
// b = a // 此行编译不通过,报错:"cannot use a (variable of type myInt) as int value in assignment"
// 如果想要编译通过,则必须将a强制转换为b的类型。
b = int(a)
fmt.Printf("a = %d,b=%d\n", a, b)
heihei := xixi
haha(100, 3.14, xixi)
haha(200, 9.18, heihei)
}
6.返回值为切片类型
package main
import (
"fmt"
)
// 当我们的一个函数返回值类型为slice时,nil可以看做是一个有效的slice,没必要显示返回一个长度为0的切片。
func someFunc(x string) []int {
if x == "" {
// 没必要返回"[]int{}",nil可以看做是一个有效的slice
return nil
}
return []int{100, 200, 300}
}
func main() {
fmt.Println(someFunc(""))
fmt.Println(someFunc("1"))
}