同步操作将从 infraboard/go-course 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
函数用于对代码块的逻辑封装,提供代码复用的最基本方式, Go中有3种函数:
Go实现了一级函数(first-class functions),Go中的函数是高阶函数(high-order functions)。这意味着:
这些特性使得函数变得无比的灵活,例如回调函数、闭包等等功能都依赖于这些特性。
Go 语言函数定义格式如下:
func function_name( [parameter list] ) [return_types] {
函数体
}
函数定义解析:
函数的参数、返回值以及它们的类型,结合起来成为函数的签名(signature)
实例: 求和函数
func sum(x int, y int) int {
return x + y
}
函数可以有0或多个参数, 参数需要指定类型, 在声明函数中若存在多个连续形参类型相同可只保留最后一个参数类型名
func sum(x, y int) int {
return x + y
}
有时候参数过多,或者想要让函数处理任意多个的参数,可以在函数定义语句的参数部分使用ARGS...TYPE
的方式。这时会将...代表的参数全部保存到一个名为ARGS的slice中,注意这些参数的数据类型都是TYPE
func max(a, b int, args ...int) int {
// 输出args中保存的参数
for index, value := range args {
fmt.Printf("%s%d%s %d\n", "args[", index, "]:", value)
}
// 取出a、b中较大者
max_value := a
if a > b {
max_value = a
}
// 取出所有参数中最大值
for _, value := range args {
if max_value < value {
max_value = value
}
}
return max_value
}
函数如果使用参数,该变量可称为函数的形参。形参就像定义在函数体内的局部变量
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数
默认情况下,Go 语言使用的是值传递(则先拷贝参数的副本,再将副本传递给函数),即在调用过程中不会影响到实际参数。
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
fmt.Printf("交换前 a 的值为 : %d\n", a )
fmt.Printf("交换前 b 的值为 : %d\n", b )
/* 通过调用函数来交换值 */
swap(a, b)
fmt.Printf("交换后 a 的值 : %d\n", a )
fmt.Printf("交换后 b 的值 : %d\n", b )
}
/* 定义相互交换值的函数 */
func swap(x, y int) {
var temp int
temp = x /* 保存 x 的值 */
x = y /* 将 y 值赋给 x */
y = temp /* 将 temp 值赋给 y*/
return;
}
引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数
由于引用类型(slice、map、interface、channel)自身就是指针,所以这些类型的值拷贝给函数参数,函数内部的参数仍然指向它们的底层数据结构。
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int= 200
fmt.Printf("交换前,a 的值 : %d\n", a )
fmt.Printf("交换前,b 的值 : %d\n", b )
/* 调用 swap() 函数
* &a 指向 a 指针,a 变量的地址
* &b 指向 b 指针,b 变量的地址
*/
swap(&a, &b)
fmt.Printf("交换后,a 的值 : %d\n", a )
fmt.Printf("交换后,b 的值 : %d\n", b )
}
func swap(x *int, y *int) {
var temp int
temp = *x /* 保存 x 地址上的值 */
*x = *y /* 将 y 值赋给 x */
*y = temp /* 将 temp 值赋给 y */
}
问题: 使用切片的过程分析程序输出结果
//定义一个函数,给切片添加一个元素
func addOne(s []int) {
s[0] = 4 // 可以改变原切片值
s = append(s, 1) // 扩容后分配了新的地址,原切片将不再受影响
s[0] = 8
}
var s1 = []int{2} // 初始化一个切片
addOne(s1) // 调用函数添加一个切片
fmt.Println(s1) // 输出一个值 [4]
函数可以有0或多个返回值, 返回值需要指定类型, 返回值通过return关键字来指定
func ParseInt(str string) (result int64, err error) {
return
}
func ParseInt(str string) (int64, error) {
var (
result int64
err error
)
return result, err
}
func add(x, y int) int {}
func add2(x, y int) (result int) {}
func ParseInt(str string) (result int64, err error) {
result = 10
return 20, nil
}
func sum(x, y int) (rest int) {
rest = x + y
return
}
func sum(x, y int) (rest int) {
return x + y
}
i, _ := strconv.ParseInt("10", 10, 64)
fmt.Println(i)
当创建函数时,你定义了函数需要做什么,通过调用该函数来执行指定任务。
调用函数,向函数传递参数,并返回值,例如:
func main() {
rest := sum(5, 6)
fmt.Println(rest)
}
在 buildin/buildin.go内定义了Go所有支持内置函数:make、len、cap、new、append、copy、close、delete、complex、real、imag、panic、recover
我们在代码里面可以直接使用: 比如使用len计算字符串的长度
package main
import (
"fmt"
)
func main() {
fmt.Println(len("asdfsdf"))
}
内置函数和用户定义函数没有本质上的区别, 我们也可以覆盖它
package main
import (
"fmt"
)
func len(a string) string {
return "hello"
}
func main() {
fmt.Println(len("asdfsdf"))
}
但是你最好不要这样做,你会被打的
函数参数可以没有名称,例如func myfunc(int,int), 一般匿名函数嵌套在函数内部,或者赋值给一个变量,或者作为一个表达式
// 声明匿名函数
func(args){
//
}
比如:
a := func(x, y int) int {
return x + y
}
fmt.Println(a(1, 2))
// 声明匿名函数并直接执行
func(args){
//
}(parameters)
比如:
a := func(x, y int) int {
return x + y
}(1, 2)
fmt.Println(a)
Go实现了一级函数(first-class functions), 函数是一个值,可以将函数赋值给变量,使得这个变量也成为函数, 因此我们也可以定义函数的类型
可以将func作为一种type,以后可以直接使用这个type来定义函数
addFunc := func(x, y int) int {
return x + y
}
fmt.Println(reflect.TypeOf(addFunc))
fmt.Println(addFunc(10, 20))
既然可以声明类型, 那么我们就可以把函数当作一个参数传递给另一个函数,比如:
type addFunc func(x, y int) int
func asArg(fn addFunc) int {
return fn(2, 2) * 2
}
func TestFuncAsArg(t *testing.T) {
ret := asArg(func(x, y int) int {
return x + y
})
fmt.Println(ret)
}
函数内部调用函数自身的函数称为递归函数
使用递归函数最重要的三点:
1.阶乘
因为阶乘的公式为n*(n-1)...321,它在参数为1的时候退出函数,也就是说它的递归基点是1,所以对是否为基点进行判断,然后再写递归表达式
// n*(n-1)*...*3*2*1
func fact(n int) int {
// 判断退出点
if n == 1 {
return 1
}
// 递归表达式
return n * fact(n-1)
}
2.斐波那契数列
它的计算公式为f(n)=f(n-1)+f(n-2)且f(2)=f(1)=1。它在参数为1和2的时候退出函数,所以它的退出点为1和2
// f(n)=f(n-1)+f(n-2)且f(2)=f(1)=1, 1 2 3 5 8 13
func fib(n int) int {
// 退出点判断
if n == 1 || n == 2 {
return 1
}
// 递归表达式
return fib(n-1) + fib(n-2)
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。