go语言中的函数定义
func functionName( [parameter list] ) [(returnName returnTypes)]) {
}
例如:
func add(a int, b int) (sum int){
sum = a+b
return
}
func add(a , b int) int{
sum := a + b
return sum
}
实际上这两种写法是等价的。第一种写法中,返回值是命了名的,这样在函数返回时可以直接返回而不用带结果。对应的C++代码为
int add(int a, int b)
{
int sum = a + b;
return sum;
}
返回值
另外go语言函数一次可以返回多个返回值,这点是C/C++做不到的,例如
func compare(a int, b int) (max int, min int){
if a > b{
max = a
min = b
}else{
max = b
min = a
}
return
}
func main(){
max, min := compare(10, 20)
return
}
比较两个数,并返回大数和小数,在这种情况下返回值命名就有它的好处了。不然我们就要记住返回的顺序,容易出错。等价于
func compare(a int, b int) (int, int){
if a > b{
return a, b
}else{
return b, a
}
}
传参
对于go语言来说一般都是传值,这点和C/C++一样,传递的是一个变量的副本,指针类型实际上也是一个变量。对于go语言来说和C语言一样只有指针类型,没有引用。例如
package main
import "fmt"
func pr(a *int) {
fmt.Println("a = ", *a)
*a = 20
}
func main() {
a := 10
pr(&a)
fmt.Println("a = ", a)
}
输出
a = 10
a = 20
对应C++代码
#include <iostream>
using namespace std;
void pr(int* a)
{
cout << "a = " << *a << endl;
*a = 20
return
}
int main()
{
int a = 10;
pr(&a);
cout << "a = " << a << endl;
reurn 0;
}
可以看得出目前为止,指针这种类型两种语言貌似没有什么区别。不过由于go语言是有垃圾回收的,所以当go的函数返回一个局部变量的指针是合法的,不像C/C++是非法的。go语言在传一些复杂的类型如map等可以看作的是传引用,原因很简单,因为go函数是传值的,所以只是把map的底层指针复制了,即C++中的浅拷贝。
匿名函数
package main
import "fmt"
func main() {
var (
a int = 10
b int = 20
)
fmt.Println("a = ", a, " b = ", b)
fun := func(p int) int {
a = 20
b = 30
fmt.Println("p = ", p)
return 0
}
fun(10)
fmt.Println("a = ", a, " b = ", b)
}
输出
a = 10 b = 20
p = 10
a = 20 b = 30
等价于C++的
#include <iostream>
#include <functional>
using namespace std;
int main(int argc, char* argv[])
{
int a = 10, b =20;
cout << "a = " << a << " b = " << b << endl;
auto fun = [&](int p)->int {
a = 20;
b = 30;
cout << "p = " << p << endl;
return 0;
};
fun(10);
cout << "a = " << a << " b = " << b << endl;
return 0;
}
可以看出,go会修改函数的外部变量,等价于c++指定传引用[&]
除此之外go语言还有一个称为闭包的匿名函数方式,行为比较奇特。请看定义
package main
import "fmt"
func getfun() func() int {
var i int
return func() int {
i++
return i
}
}
func main() {
fun1 := getfun()
fmt.Println("call fun1 ", fun1())
fmt.Println("call fun1 ", fun1())
fmt.Println("call fun1 ", fun1())
fun2 := getfun()
fmt.Println("call fun2 ", fun2())
fmt.Println("call fun2 ", fun2())
fmt.Println("call fun2 ", fun2())
}
输出
call fun1 1
call fun1 2
call fun1 3
call fun2 1
call fun2 2
call fun2 3
等价于C++中
#include <iostream>
#include <functional>
using namespace std;
function<int()> getfun()
{
int& i = *(new int);
i = 0;
auto fun = [&]()->int {
i++;
return i;
};
return fun;
}
int main(int argc, char* argv[])
{
auto fun1 = getfun();
cout << "call fun1 " << fun1() << endl;
cout << "call fun1 " << fun1() << endl;
cout << "call fun1 " << fun1() << endl;
auto fun2 = getfun();
cout << "call fun2 " << fun2() << endl;
cout << "call fun2 " << fun2() << endl;
cout << "call fun2 " << fun2() << endl;
return 0;
}
虽然行为上一致,但是可以看出两门语言有很多区别
区别一、go语言中的局部变量的生存周期可以在函数退出后继续存在。这里面就是i,C++为了模拟这个情况,我特意让这个i是new出来,并产生了严重的内存泄露
区别二、go语言会自动将局部变量初始化为0,但是C++,必须明确的赋值为0
不过目前还没有想到这种闭包的用途,希望大神指点。
另外就是函数作为方法,这有点像C++的类中的方法。等到介绍结构体时我再说明。
最后,我学go语言才几天时间,只是粗粗的看了些语法,写这个系列的博客也是为了自己学习。所以可能会存在很多的错误。对这门语言的认识也不会有多深,还是烦请各路大神不吝赐教。谢谢。