goLang函数

2019-07-17
0 评论 385 浏览

函数

import (
	"fmt"
	"reflect"
	"testing"
)
//num 为切片类型
func sum(num ...int) int {
	s := 0
	fmt.Printf("num的类型为:%q\n",reflect.TypeOf(num))
	for _, n := range num {
		s += n
	}
	return s
}
func TestNumSum(t *testing.T) {
	sum := sum(1, 2, 3, 4, 5, 6, 7, 8, 9)
	t.Log(sum)
}

运行结果:

num的类型为:"[]int"
--- PASS: TestNumSum (0.00s)
    func_test.go:19: 45

函数是第一类对象,可作为参数传递。只要被调用函数的返回值个数,返回值类型和返回值的顺序与被调函数所需求的实参是一致的,就可以把这个被调的函数当作其他函数的参数。
假设f1需要3个参数,同时f2返回3个参数,就可以像下面这样的方式去调用

package main

import "fmt"

//传入两个数和第三个数做比较,返回最大值
func main() {
	fmt.Println(f1(two(1, 2)))
}
func two(a, b int) (a1, b1, c1 int) {
	c := a + b
	return a, b, c
}
func f1(a1, b1, c1 int) int {
	return a1 + b1 + c1
}

可变参数

有时候我们传入函数的参数的个数我们并不能保证,Go语言函数支持可变参数(简称变参)为了实现这一点,首先需要定义函数的时候使其接收变参:

func myFuncName(agr ...type) {}

函数的最后一个参数如果是...type的形式,那这个函数就是一个变参函数,它可以处理变长的参数,而这个长度可以为0。在变参函数中,无论变参有多少个,他们的类型必须全部一样

package main

import "fmt"

//编写一个传入多个年龄值然后返回最大年龄或者最小年龄
func main() {
	//手动输入比大比小
	Str := "max"
	age := []int{1, 2, 3, 4, 5}
	fmt.Println(Comparison(Str,1,2,3,4,5,6))
	//把切片的值当作变参
	fmt.Println(Comparison(Str,age...))
}
func Comparison(s string, Age ...int) int {
	var num int
	if len(Age) == 0 {
		return 0
	}
	if s == "mix" {
		for i, _ := range Age {
			num = Age[0]
			if Age[i] < num {
				num = Age[i]
			}
		}
	} else if s == "max" {
		for i, _ := range Age {
			num = Age[0]
			if Age[i] > num {
				num = Age[i]
			}
		}
	}
	return num
}

上面我们也提到了,变参的类型必须一样,但是如果我们不想让他们一样呢,那么我们就需要用的特殊的类型interface{}接口类型,来传递不同基础类型的值

package main

import "fmt"

func main() {
	interfaceArgs("Name", "张首富", 1, 1.0)
}
func interfaceArgs(args ...interface{}) {
	for _, v := range args {
		fmt.Println(v)
	}
}

匿名函数与闭包

匿名函数是指不需要定义函数名的一种函数定义方式,因为函数声明并没有命名函数名称,所以这样的一个函数不能独立存在,但可以被赋值于某个变量,即保存函数的地址到变量中

package main

import "fmt"

func main() {
	//把函数赋值给某个变量。实际上是吧函数的地址赋值给变量
	fplus := func(a int, b int) int { return a + b }
	fmt.Println(fplus(3, 4))
}

我们也可以直接定义直接调用

package main

import "fmt"

func main() {
	func(num int) int {
		sum := 0
		for i := 1; i <= num; i++ {
			sum += i
		}
		fmt.Println(sum)
		return sum
	}(100)
}

运行结果:

5050

参数列表的第一对括号必须紧挨着关键字func,因为匿名函数没有名称。花括号{}涵盖着函数体,最后的一对括号表示对该匿名函数的调用。

递归函数

从名称中我们就可以看出,递归函数就是函数自己调用自己本身。go语言支持递归,但在使用递归时,我们需要设置退出条件,否递归将陷入无限循环,

//阶乘
package main

import "fmt"

func Factorial(n int) int {
	if n < 2 {
		return n
	}
	return n * Factorial(n-1)
}
func main() {

	fmt.Println(Factorial(15))

}

运行结果:

1307674368000

go语言实现斐波那契数列
使用递归函数来完成斐波那契数列:

package main

import "fmt"
//使用递归函数来完成斐波那契数列
func Fibonacci(n int) int {
	if n < 2 {
		return n
	}
	return Fibonacci(n-2) + Fibonacci(n-1)
}
func main() {
	for i := 0; i <= 10; i++ {
		fmt.Printf("%d\t", Fibonacci(i))
	}
}

传统方式实现:

package main
import "fmt"

func main() {
	a, b := 0, 1
	var c int
	fmt.Printf("%d\t%d\t", a, b)
	for i := 2; i <= 10; i++ {
		c = a + b
		fmt.Printf("%d\t", c)
		a = b
		b = c
	}
}

运行结果:

0	1	1	2	3	5	8	13	21	34	55

内置函数

内置函数就是不需要进行导入操作就可以直接使用的函数,他们有些可以根据不同的类型进行操作(cap,len,append),有些用于系统级的操作(panic)。他们都需要编译器的直接支持
常见的内置函数:
* close:用于管道通信
* len:用于返回某个类型的长度或数量(字符串,数组,切片,map和管道)
* cap:容量,用于返回某个类型的最大容量,(只用于切片和map)
* new,make:均用于分配内存,不过new用于值类型和用户定义的类型,如定义结构,make用于内置饮用可类型(切片,map,管道)他们的用法就像是函数,但是将结构作为参数:new(type),make(type).new(T)分配类型T的零值并返回其地址,也就是指向类型T的指针,他也可以用于基本类型: v:=new(int)
* copy,append: 用于复制和连接切片,向切片里面添加数据
* panic、recover:两者均用于错误处理机制
* print、println:底层打印函数,建议使用fmt
* complex、real image:用于创建和操作复数

参数传递机制(按值传递 or 按引用传递)

defer与跟踪

defer延迟语句

当函数执行到最后时(return/关闭之前)这些defer语句会按照逆序,后进先出的方式执行,执行完成之后才会退出函数,
1)defer的用途
我们在执行一些类似于IO操作的时候,如果遇到错误,我们需要提前返回,返回的时候应该关闭打开的文件,否则容易造成资源泄漏等问题,defer语句就可以出色的解决这个问题
defer后面制定的函数会在函数退出前调用,如果是多次调用defer,那么defer就会采取先进后出的模式来

package main

import (
	"fmt"
)

func main() {
	fmt.Println(sum(3, 5))
}
func sum(a, b int) int {
	defer fmt.Println(1)
	defer fmt.Println(3)
	if a > b {
		return a + b
	} else {
		return a * b
	}
}

输出结果为:

3
1
15

2)执行顺序
特别注意的是函数的返回值是否被命令
a,函数返回值未被命令

package main

import (
	"fmt"
)

func main() {
	fmt.Println(str())
}
func str() int {
	var i int
	defer func() {
		i++
		fmt.Println("defer1", i)
	}()
	defer func() {
		i++
		fmt.Println("defer2", i)
	}()
	return i
}

执行得到的结果为:

defer2 1
defer1 2
0

b,返回值带名称

package main

import (
	"fmt"
)

func main() {
	fmt.Println(str())
}
func str() (i int) {

	defer func() {
		i++
		fmt.Println("defer1", i)
	}()
	defer func() {
		i++
		fmt.Println("defer2", i)
	}()
	return i
}

运行结果为:

defer2 1
defer1 2
2

评论
发表评论