目录
函数
GO函数特点:
- 无需声明原型。
- 支持不定 变参。
- 返回值类型写在最后面,支持多返回值。
- 支持命名返回参数。
- 支持匿名函数和闭包。
- 函数也是一种类型,一个函数可以赋值给变量。
- 不支持 嵌套 (nested) 一个包不能有两个名字一样的函数。
- 不支持 重载 (overload)
- 不支持 默认参数 (default parameter)、可选参数
- 参数传递:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝。
- 使用关键字 func 定义函数,左大括号依旧不能另起一行
Go函数声明:
-
package main
-
-
import
"fmt"
-
-
func test(fn func() int) int {
-
return fn()
-
}
-
// 定义函数类型。
-
type FormatFunc
func(s string, x, y int) string
-
-
func
format
(fn FormatFunc, s string, x, y int)
string {
-
return fn(s, x, y)
-
}
-
-
func main() {
-
s1 := test(
func() int {
return
100 })
// 直接将匿名函数当参数。
-
-
s2 := format(
func(s string, x, y int) string {
-
return fmt.Sprintf(s, x, y)
-
},
"%d, %d",
10,
20)
-
-
println(s1, s2)
-
}
-
-
// 返回结果
-
// 100 10, 20
GO函数参数
函数可以通过两种方式来传递参数:
- 值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
- 引用传递:是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
- 在默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。
注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。
注意2:map、slice、chan、指针、interface默认以引用的方式传递。
任意类型的不定参数: 就是函数的参数和每个参数的类型都不是固定的。
用interface{}传递任意类型数据是Go语言的惯例用法,而且interface{}是类型安全的。
-
func myfunc(args ...interface{}) {
-
}
使用 slice 对象做变参时,必须展开。(slice...)
-
package main
-
-
import
(
-
"fmt"
-
)
-
-
func
test
(s string, n ...int) string {
-
var x
int
-
for _, i := range n {
-
x += i
-
}
-
-
return fmt.Sprintf(s, x)
-
}
-
-
func main() {
-
s := []
int{
1,
2,
3}
-
res := test(
"sum: %d", s...)
// slice... 展开slice
-
println(res)
-
}
GO函数返回值
"_"
标识符,用来忽略函数的某个返回值- Go 的返回值可以被命名,并且就像在函数体开头声明的变量那样使用。
- 返回值的名称应当具有一定的意义,可以作为文档使用。
匿名函数
匿名函数是指不需要定义函数名的一种函数实现方式。
在Go里面,函数可以像普通变量一样被传递或使用,Go语言支持随时在代码里定义匿名函数。
匿名函数由一个不带函数名的函数声明和函数体组成。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
-
package main
-
-
import (
-
"fmt"
-
"math"
-
)
-
-
func main() {
-
getSqrt :=
func(a float64) float64 {
-
return math.Sqrt(a)
-
}
-
fmt.Println(getSqrt(
4))
-
}
-
-
// 返回
-
// 2
上面先定义了一个名为getSqrt 的变量,初始化该变量时和之前的变量初始化有些不同,使用了func,func是定义函数的,可是这个函数和上面说的函数最大不同就是没有函数名,也就是匿名函数。这里将一个函数当做一个变量一样的操作。
Golang匿名函数可赋值给变量,做为结构字段,或者在 channel 里传送。
-
package main
-
-
func main() {
-
// --- function variable ---
-
fn :=
func() {
println(
"Hello, World!") }
-
fn()
-
-
// --- function collection ---
-
fns := [](
func(x int) int){
-
func(x int) int {
return x +
1 },
-
func(x int) int {
return x +
2 },
-
}
-
println(fns[
0](
100))
-
-
// --- function as field ---
-
d :=
struct {
-
fn
func() string
-
}{
-
fn:
func() string {
return
"Hello, World!" },
-
}
-
println(d.fn())
-
-
// --- channel of function ---
-
fc :=
make(
chan
func() string, 2)
-
fc <-
func
()
string {
return
"Hello, World!" }
-
println((<-fc)())
-
}
输出结果:
-
Hello, World!
-
101
-
Hello, World!
-
Hello, World!
闭包
闭包是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)。
Go的闭包
-
package main
-
-
import (
-
"fmt"
-
)
-
-
func a() func() int {
-
i :=
0
-
b :=
func() int {
-
i++
-
fmt.Println(i)
-
return i
-
}
-
return b
-
}
-
-
func main() {
-
c := a()
-
c()
-
c()
-
c()
-
-
fmt.Println(
"a() //不会输出i")
-
a()
//不会输出i
-
-
c2 := a()
-
c2()
-
c2()
-
c2()
-
-
//输出结果
-
//1
-
//2
-
//3
-
//a() //不会输出i
-
//1
-
//2
-
//3
-
}
这段代码有两个特点:
函数b嵌套在函数a内部 函数a返回函数b 这样在执行完var c=a()后,变量c实际上是指向了函数b(),再执行函数c()后就会显示i的值,第一次为1,第二次为2,第三次为3,以此类推。 其实,这段代码就创建了一个闭包。因为函数a()外的变量c引用了函数a()内的函数b(),就是说:
当函数a()的内部函数b()被函数a()外的一个变量引用的时候,就创建了一个闭包。 在上面的例子中,由于闭包的存在使得函数a()返回后,a中的i始终存在,这样每次执行c(),i都是自加1后的值。 从上面可以看出闭包的作用就是在a()执行完并返回后,闭包使得go的垃圾回收机制GC不会收回a()所占用的资源,因为a()的内部函数b()的执行需要依赖a()中的变量i。
在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。变量的作用域仅限于包含它们的函数,因此无法从其它程序代码部分进行访问。不过,变量的生存期是可以很长,在一次函数调用期间所创建所生成的值在下次函数调用时仍然存在。正因为这一特点,闭包可以用来完成信息隐藏,并进而应用于需要状态表达的某些编程范型中。
下面来想象另一种情况,如果a()返回的不是函数b(),情况就完全不同了。因为a()执行完后,b()没有被返回给a()的外界,只是被a()所引用,而此时a()也只会被b()引 用,因此函数a()和b()互相引用但又不被外界打扰(被外界引用),函数a和b就会被GC回收。所以直接调用a();是页面并没有信息输出。
下面来说闭包的另一要素引用环境。c()跟c2()引用的是不同的环境,在调用i++时修改的不是同一个i,因此两次的输出都是1。函数a()每进入一次,就形成了一个新的环境,对应的闭包中,函数都是同一个函数,环境却是引用不同的环境。这和c()和c()的调用顺序都是无关的。
递归函数
递归,就是在运行的过程中调用自己。 一个函数调用自己,就叫做递归函数。
构成递归需具备的条件:
-
1.子问题须与原始问题为同样的事,且更为简单。
-
2.不能无限制地调用本身,须有个出口,化简为非递归状况处理。
斐波那契数列(Fibonacci)
这个数列从第3项开始,每一项都等于前两项之和。
-
package main
-
-
import
"fmt"
-
-
func fibonaci(i int) int {
-
if i ==
0 {
-
return
0
-
}
-
if i ==
1 {
-
return
1
-
}
-
return fibonaci(i
-1) + fibonaci(i
-2)
-
}
-
-
func main() {
-
var i
int
-
for i =
0; i <
10; i++ {
-
fmt.Printf(
"%d\n", fibonaci(i))
-
}
-
}
输出结果:
-
0
-
1
-
1
-
2
-
3
-
5
-
8
-
13
-
21
-
34
转载:https://blog.csdn.net/fly910905/article/details/104460565