[TOC]
1 函数定义&参数
函数用于对代码块的逻辑封装,提供代码复用的最基本方式,函数是对代码的一个封装,和复用
1.1 定义函数
函数包含函数名、形参参列表、函数体和返回值列表,使用 func
进形参声明,函数无参数或返回值时则形参列表和返回值列表省略。
函数可以理解为就是一种类型
func 函数名称(形参) 返回值 {
函数体
}
/* 1. 形参:可以认为就是我们的变量,参数用于接收传递进来的数据的
参数传递 => 变量赋值的过程
2. 当函数调用传递的参数 => 叫做实参
3. 在 go 返回值时强类型的,所以在定义的时候也需要指定他的返回值类型
*/
范例无参函数:
package main
import "fmt"
func sayHello() {
fmt.Println("hello")
}
// 这个函数就是没有形参参和返回值得函数
func main() {
// 主函数中调用 sayHello() 函数
sayHello()
}
[14:57:53 root@go day1]#go run main.go
hello
有参函数无返回值范例:
package main
import "fmt"
// 有参数,无返回值
func sayHi(name string) {
fmt.Println("hello ,", name)
}
func main() {
sayHi("tom")
}
[14:59:05 root@go day1]#go run main.go
hello , tom
通过变量传递:
package main
import "fmt"
func sayHello() {
fmt.Println("hello")
}
// 有参数,无返回值
func sayHi(name string) {
fmt.Printf("hi %v\n", name)
}
func main() {
// 虽然这个 name 和 sayHi 中的形参参变量名一样,但是这里作用域不一样依旧可以传递
name := "zz"
sayHi(name)
}
[14:59:47 root@go day1]#go run main.go
hi zz
返回值函数范例:
package main
import "fmt"
// 返回值函数
func Add(a int, b int) int {
return a + b
}
func main() {
// 定义 res 变量接收 Add 函数的返回值
// 实参会按照顺序传递给函数的形参参
res := Add(1, 2)
fmt.Println(res)
}
[14:59:47 root@go day1]#go run main.go
3
1.2 类型合并
当多个连续的形参参类型相同时定义范例:
参数合并范例 1:
package main
import "fmt"
/* 在函数中连续多个形参参类型是一样的时候
只保留最后一个类型,前面连续相同的数据类型可省略
和定义多个变量数据类型相同的时候操作一样 var a int , b int => var a , b int
*/
func Add(a, b int) int {
return a + b
}
func main() {
res := Add(1, 2)
fmt.Println(res)
}
[14:59:47 root@go day1]#go run main.go
3
参数合并范例 2 :
package main
import "fmt"
// 由于 a , b 两个形参连续所以这两个是 string 类型
func test(a, b string, c int) {
fmt.Printf("a = %T b = %T c = %T\n", a, b, c)
}
func main() {
test("1", "2", 3)
}
[15:21:06 root@go day1]#go run main.go
a = string b = string c = int
1.3 可变参数:
在一个函数中只能定义一个可变参数,不能定义多个可变参数,并且这个可变参数只能够在函数形参参的最后
所谓的可变参数,就是在传递形参的时候后面的参数可传递可不传递
package main
import "fmt"
// 这样就必须使用一致的数据类型
// 这里的意思 a , b 是必须传递的(因为指定了 a b 形参参),但是后面的 args 可传递可不传递
// 可变参数 args 就是一个切片类型
func AddAll(a, b int, args ...int) {
fmt.Println(a, b, args)
fmt.Printf("%T\n", args)
fmt.Println()
}
func main() {
AddAll(1, 2) // 传递 两个实参的时候 args 就是 0 个元素
AddAll(1, 2, 3) // 传递 三个实参的时候 args 就是 1 个元素
AddAll(1, 2, 3, 4) // 传递 多个实参的时候 args 就是 多 个元素
}
[15:21:53 root@go day1]#go run main.go
1 2 []
[]int
1 2 [3]
[]int
1 2 [3 4]
[]int
可变参数返回值
如何实现多个参数的返回值
package main
import "fmt"
func AddAll(a, b int, args ...int) int {
// 定义临时 temp 变量
temp := 0
// 由于 args 是一个切片,直接遍历 args 的值累加个 temp
for _, v := range args {
temp += v
}
sum := a + b + temp
return sum
}
func main() {
res := AddAll(1, 2, 3, 4)
fmt.Println(res)
}
[15:22:58 root@go day1]#go run main.go
10
将切片传递给可变参数
解包
我们在传递切片的时候需要先对形参解包
package main
import "fmt"
func AddAll(a, b int, args ...int) int {
fmt.Println(a, b, args)
res := a + b
// 遍历 args 取出每个元素,累加给 res
for _, v := range args {
res += v
}
return res
}
func main() {
// 定义 nums 的一个切片并赋值
nums := []int{2, 3, 4, 5}
// 传递 1,2,nums... ,其中 nums... 就是解包
fmt.Println(AddAll(1, 2, nums...))
}
[16:18:13 root@go day1]#go run main.go
1 2 [2 3 4 5]
17
函数调用解包操作
package main
import "fmt"
func AddAll(a, b int, args ...int) {
// 传给 print 函数 args 可变参数
print(args...)
}
// 定义 print 函数,形参是可变参数
func print(args ...int) {
for i, v := range args {
fmt.Println(i, v)
}
}
func main() {
nums := []int{2, 3, 4, 5}
AddAll(1, 2, nums...)
}
[17:11:26 root@go day1]#go run main.go
0 2
1 3
2 4
3 5
2 函数返回值+函数总结+函数练习(冒泡)
函数:
定义:
func 函数名(形参) 返回值 {
函数体
}
函数名:满足标识符规范
形参:无形参
有形参:名字类型,多个形参使用逗号分隔
连续多个形参类型一致 => 合并参数类型
可以接受任何多个变量 => 可变参数
返回值:
无返回值:
返回值省略
有返回值:
return 关键字
必须指定返回值类型
返回值非命名方式:
只有一个返回值:返回值只需要写类型,可以省略小括号
有多个返回值:需要 () 包含所有返回值类型
return 返回值数量必须和函数定义返回值类型数量一致
命名方式:
返回值定义值为每个返回值指定变量名称及变量类型,用 () 包含
返回是只用 return 即可
若连续多个返回值类型相同 => 返回值类型合并
调用:
接收返回值 = 函数名(实参)
非可变参数:
实参数量必须与形参一致 => 实参按照顺序传递给形参
可变参数:
可变参数定义之前的变量 必须 指定实参传递
可变参数部分可以传递任意多个值(可使用切片解包)
返回值:
无返回值不能接收
有返回值 必须用相同数量的变量接收返回值(按照返回值的顺序赋值给接收的变量)
在函数提中可以使用 return 关键字为函数调用这提供函数计算结果
有返回值和没有返回值都可以使用
函数返回值可以不调用
package main
func Add(a, b int) int {
return a + b
}
func main() {
// 没有调用函数返回值
Add(1, 2)
}
函数调用返回值
package main
import "fmt"
func Add(a, b int) int {
return a + b
}
func main() {
// 将返回值重新赋值给 c 变量
c := Add(1, 2)
fmt.Println(c)
}
[17:20:03 root@go day1]#go run main.go
3
2.1 多个返回值
函数多个返回值
package main
import "fmt"
// 返回多个结果
// a + b , a - b , a * b , a / b
// 多个返回值就用 () 括起来
func op(a, b int) (int, int, int, int) {
// 4 个返回值
return a + b, a - b, a * b, a / b
}
func main() {
// 需要通过 4 个变量来接收返回值,逗号隔开
res, res1, res2, res3 := op(4, 2)
fmt.Println(res, res1, res2, res3)
}
[17:41:09 root@go day1]#go run main.go
6 2 8 2
定义函数的返回值的时候,定义了几个返回值就需要用几个变量来接收
cannot initialize 3 variables with 4 valuescompiler
:无法用4个值初始化3个变量
2.2 命名返回值
在函数返回值列表中可指定变量名,变量在调用时会根据类型使用零值进形参初始化,在函数体中可进行形参赋值,同时在调用 return 时不需要添加返回值,go 语言自动将变量的最终结果以形参返回,在使用命名返回值时,当声明函数中存在若多个连续返回值类型相同可只保留最后一个返回值类型名
命名返回值使用情况是代码比较简单的时候建议使用,如果比较复杂就不建议使用
package main
import (
"fmt"
)
// 命名返回值
func op(a, b int) (sum int, sub int, mul int, div int) {
sum = a + b
sub = a - b
mul = a * b
div = a / b
// 直接返回
return
}
func main() {
res, res1, res2, res3 := op(4, 2)
fmt.Println(res, res1, res2, res3)
}
[17:42:16 root@go day1]#go run main.go
6 2 8 2
当我们的多个返回值类型相同时,也可以使用类型合并
package main
import (
"fmt"
)
// 匿名返回值
// sum, sub, mul, div int 类型合并
func op(a, b int) (sum, sub, mul, div int) {
sum = a + b
sub = a - b
mul = a * b
div = a / b
// 直接返回
return
}
func main() {
res, res1, res2, res3 := op(4, 2)
fmt.Println(res, res1, res2, res3)
}
[17:42:16 root@go day1]#go run main.go
6 2 8 2
2.3 冒泡排序
package main
import "fmt"
func main() {
nums := []int{1, 4, 3, 2}
for i := 0; i < len(nums); i++ {
for j := 0; j < len(nums)-1; j++ {
if nums[j] > nums[j+1] {
nums[j], nums[j+1] = nums[j+1], nums[j]
}
}
}
fmt.Println(nums)
}
[18:02:31 root@go day1]#go run main.go
[1 2 3 4]
2.3.1 编写冒泡排序函数
函数用于代码的复用性,复用了 sort 切片
由于切片是引用类型,所以当函数里面的 nums 修改了,就会影响 nums 本身的元素值
package main
import "fmt"
// 编写一个 sort 函数
func sort(nums []int) {
for i := 0; i < len(nums); i++ {
for j := 0; j < len(nums)-1; j++ {
if nums[j] > nums[j+1] {
nums[j], nums[j+1] = nums[j+1], nums[j]
}
}
}
}
func main() {
// 定义了 nums 切片
slice := []int{1, 23, 442, 33, 5}
sort(slice)
fmt.Println(slice)
// 定义了 nums 切片
nums2 := []int{100, 23, 33, 44, 59}
sort(nums2)
fmt.Println(nums2)
}
[18:08:42 root@go day1]#go run main.go
[1 5 23 33 442]
[23 33 44 59 100]