学习go语言之前,我们应该知道go语言是一个函数式编程语言,函数是重中之重,所以本部分介绍了Go语言基本的函数用法以及,为什么说go语言是一个函数式编程语言
一个简单函数
在go语言中,函数的命名方式与变量相同,都是关键字,函数名、类型这种,类型写在最后的方式
函数具体写法如下:
func eval(a, b, int,op string) int{
...
}
下面是一个简单的函数写法及调用方法:
package main
import (
"fmt"
)
func eval(a, b int, op string) int {
switch op {
case "+":
return a+b
case "-":
return a-b
case "/":
return a/b
case "*":
return a*b
default:
panic("unsupported operation: "+op)
}
}
func main(){
fmt.Println(eval(3, 4, "*"))
}
多返回值的函数
先看一个两个返回值的函数
在go语言中,前面也提到过,go语言支持多个返回值,现在介绍的是go语言的,两个返回值的写法:
// 两个返回值的函数
func div(a,b int) (int,int){ // 带余数除法
return a/b, a%b
}
如上,在两个返回值的函数写法中,在定义返回值类型的地方再写一个返回值的类型即可
返回值分不清?来起个名吧
go语言支持为函数的返回值起名字,具体的写法如下:
package main
import (
"fmt"
)
// 给返回值起名
func div(a,b int) (q,r int){// 带余数除法
//方法一:
q = a/b
r=a%b
return
// 方法二:
return a/b, a%b
}
func main(){
q, r := div(13,3) //:=定义它们
fmt.Println(q, r)
}
上述代码可以看出对返回值起名时遵循变量定义时,变量在前,类型在后的方式,在函数体中存在这么两种写法
方法一指定两个返回值q,r分别代表什么,然后返回;
方法二不指定具体代表,按照默认先后顺序进行返回,在主函数体内选取变量进行接受;函数返回值q,r与主函数内接收的q,r没有关联,变量名随意取,不要求相同
注意上述代码返回值代码内起名这种方式仅仅用于简单函数,复杂函数会增加代码复杂度,对调用者而言没有区别
函数返回错误
在其他语言中函数执行报错时会中断整个程序,而go语言可以自定义返回错误信息,并借助多返回值的优势,帮助使用者调试代码
修改一下上次说到的四则运算代码,示例:
package main
import (
"fmt"
"math"
"reflect"
"runtime"
)
func div(a,b int) (q,r int){
return a/b, a%b
}
func eval2(a, b int, op string) (int, error) {
switch op {
case "+":
return a+b,nil
case "-":
return a-b,nil
case "*":
return a*b,nil
case "/":
//多返回值使用‘_’表示接受不使用
q, _ := div(a,b)
return q,nil
default:
// panic("unsupported operation: "+op)
return 0,fmt.Errorf("unsupported operation: %s", op)
// 自定义错误信息输出
}
}
func main(){
if result, err := eval2(3, 4, "/");err==nil{
fmt.Println(result)
}else{
fmt.Println("Error: ", err)
}
}
上述代码中,函数拥有两个返回值int
类型和erroe
类型,由于go语言中定义的变量必须使用,所以在每个返回值后面,再多返回一个nil表示error类型返回值,且无错误;
在主函数的if
中调用eval2
函数,按照switch逻辑,将调用div函数进行运算,并返回两个返回值,查看代码我们可以发现div也是两个返回值,如果我们只想要其中的一个返回值的时候应该怎么办呢?
类似与下面一句代码,当我们不想要某个返回值时只需要使用_
便可以表示接收不使用
q, _ := div(a,b)
回到刚刚的话题,刚刚定于的error
类型如何使用呢?从代码来看,如果我们输入参数eval2(3, 4, "z")
,很明显,我们定义的eval2
函数没法处理z
这个参数,这时候就会触发default
中定义的error处理
default
中的return首先将int类型返回值返回一个0,然后使用fmt.Errorf
错误信息输出语句输出错误参数并返回到主程序中并使用err
接收,if判断err不为nil,则输出正常运行结果,否则运行自定义错误信息
go——函数式编程语言
go语言相交之C++等其他语言,没有默认参数、可选参数、函数重载等花哨的用法
仅有可变参数列表
这一种用法,关于这两点我们通过两段代码验证一下
参数可以为函数
package main
import (
"fmt"
"math"
"reflect"
"runtime"
)
// go语言是一个函数式编程语言,体现如下,函数内的函数
func apply(op func(int, int) int, a,b int) int {
p := reflect.ValueOf(op).Pointer()
opName := runtime.FuncForPC(p).Name()
// 获得函数名
fmt.Printf("函数名是: %s" + "(%d, %d)\n", opName, a, b)
return op(a,b)
}
func Pow(a,b int) int{
return int(math.Pow(float64(a), float64(b)))
}
func main(){
//fmt.Println(apply(Pow, 3 , 4))
// 函数直接写在调用处,匿名函数,无需写函数名
fmt.Println(apply(
func(a,b int) int{
return int(math.Pow(float64(a), float64(b)))
},3 , 4))
fmt.Println(sum(1,2,3,4,5))
}
如上代码,观察函数apply
,包含三个参数和一个返回值,其中,第一个参数是一个函数,这个函数拥有两个参数和一个返回值
这三个参数在函数D调用时,以D(A,B,C)的形式调用
apply(Pow, 3 , 4)
这句话便是一个举例用法,Pow为传入的函数名,3,4是其他参数,首先apply获取到传入并运行的实际的函数名称(此处是Pow),然后输出函数名和传入的另外两个参数,在return处调用参数函数op,即Pow
Pow的参数便是a,b
实际上main中调用部分传入的Pow甚至不需要提前定义
可以写成如下这样
// 函数直接写在调用处,匿名函数,无需写函数名
fmt.Println(apply(
func(a,b int) int{
return int(math.Pow(float64(a), float64(b)))
},3 , 4))
采用匿名函数的方式,直接将函数写在调用处,此方法不需要写传入的函数名
可变参数列表
关于这部分比较简单,只需要记住...
即可,在go语言中...
代表无限制参数数量
package main
import (
"fmt"
"math"
"reflect"
"runtime"
)
func sum(numbers ...int) int{
//...代表任意数量参数
s:=0
for i:=range numbers{
s+=numbers[i]
}
return s
}
func main(){
fmt.Println(sum(1,2,3,4,5))
}