Golang语言之函数(func)基础篇

                                              作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

一.函数的引入

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"))
}

posted @ 2024-07-13 00:15  尹正杰  阅读(243)  评论(0编辑  收藏  举报