一、前言
函数非常重要,并且我们在数学中早就接触过函数了。
比如,明明y=2x+5
这样简单的函数,为什么数学书上常常会出现下面这样的写法呢?
y=f(x)
f(x)=2x+5
我相信很多人以前其实是根本没有细想过的,甚至觉得这明显就是多此一举。
但待你深入学习数学、乃至其它学科,逐渐你会发现,这样写是有其原因的。
任何领域想要长足的发展,都需要有一定的体系结构,而这些体系结构中会有大量重复、低层次的内容,如果不将其压缩,就会造成后续升级繁琐。
比如,乘法就是对加法的压缩,当你想要计算100*100
时,你不会想到用100个100去相加,因为那样太繁琐。
同样的,专业领域一般都有属于自己的专有名词,比如计算机领域就有硬盘、内存等,它们的作用同样是压缩信息,这样你就不用每次交流都说出一大堆描述性的词来描述这个东西。
也许例子不太恰当,但想来你应该能理解我的意思。
函数对于编程的意义很大程度上也在于此:压缩低层次、相对固定不变的内容,日后直接通过函数名使用即可。
二、深入理解
虽然不同语言中对于函数的实现方法并不相同,但大体可以将函数分为三个部分:
- 参数
- 内部执行语句
- 返回值
也就是说,只要有了上面这三个部分,其实就可以定义一个函数了,比如C/C++中的函数:
返回值 name(参数){
执行语句
}
比如rust中的函数:
fn funname(参数)-> 返回值{
执行语句
}
函数名只是函数的一个标识,是用来寻找这个函数位置的,比如很多语言中都存在匿名函数,就是只使用一次的函数,那就没必要使用函数名,因为它并不是必要的。
更进一步抽象的说,函数其实你也可以理解为一个对象,而函数名,实际上就是这个对象的名称,就和普通的变量没什么区别。
这一点在js代码中就非常常见:
let a=10;
let f=()=>{}
上面这句话就是让f
变量等于一个函数,()
中存放函数参数,{}
中存放执行语句,至于返回值则不需要写,因为js中是在运行时推断的。
上面介绍的都是声明函数,也就是告诉程序我写了这个函数,而想要执行它,基本都是通过下面这种代码形式:
int ret=funName(参数);
也就是通过函数名+参数的形式来执行函数,然后将执行的结果交给最前面的变量。
对于函数来书,很多语言还存在函数重载,典型的代表就是C++
,它可以允许你用一个函数名定义多个函数。
但事实上,这多个函数依旧是不同的函数,并且变量名也不会相同,因为C++编译器在编译的时候会根据你函数的参数来修改你的函数名。
这也是为什么C++中重载函数的参数个数、类型、顺序不能完全相同的原因。
至于类函数,其实也是一个普通的函数,只不过它指定了第一个参数为this
指针,也就是当前变量的实例,且不需要我们填。
比如一个类:
class Test{
public:
void fun(int a){}
}
如果能拿到fun函数的地址,那么下面两种写法其实是等价的:
Test t;
t.fun(100);
pfun=&fun; //假设拿到了fun函数的地址
pfun(&t,100);//与上面写法实际上是等价的。
这在rust、go等现代化语言中就可以很好的看出来,它们不再支持类,但允许你使用结构体绑定函数。