1、函数对象与闭包的误区
有一些编程语言中提供了函数对象这一概念,我知道有些把这个叫做闭包(Closure),但其实这种理解是不准确的,因为函数对象不一定是闭包。不过话说回来,要理解闭包,首先要理解函数对象。
函数对象是作为对象来使用的函数。不过,这里的对象不一定是面向对象中所指的那个对象,而更像是编程语言所操作的数据这个意思。
C语言的函数对象
#include <stdio.h> int two(int x) { return x*2; } int three(int x) { return x*3; } int main(int argc,char **argv) { int (*times)(int); int n=2; if(argc==1)times=two; else times=three; printf("times(%d)=%d ",n,times(n)); }
C语言中,我们可以获取一个函数的指针,并通过指针间接调用该函数。这就是C语言概念中的对象。
int (*times)(int);
这是对指针型变量times的声明:变量times,是指向一个拥有一个int型参数,并返回int值的函数的指针。
其中if语句:当传递给程序的命令行参数为0个时,将函数two(的指针)赋值给变量times;
一个以上,则将函数three的指针赋值给times。
2、函数对象对编程的用途
函数对象,也就是将函数作为值来利用的方法,其最大的用途就是高阶函数。
所谓高阶函数,就是用函数作为参数的函数。
设想一个对数组排序的函数。这个函数是用C语言编写的,在API设计上,应该写成这样:
void sort(int *a,size_t size);
函数接受一个大小为size的整数数组a,并对其内容进行排序。
其缺乏通用性:
a)只能对整数数组进行排序;
b)排序条件无法从外部进行指定。
在C语言标准库中,却提供了一个具有通用性的排序函数:qsort。
void qsort(void *base,size_t nmemb,size_t size,int(*compar)(const void *,const void *));
#ifndef _CRT_ALGO_DEFINED
#define _CRT_ALGO_DEFINED
void *__cdecl bsearch(const void *_Key,const void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *));
void __cdecl qsort(void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *));
#endif
那么这个通用排序函数qsort是如何克服上述这两个缺点的呢?秘密就隐藏在qsort函数的参数中。
参数base,类型void *,可以接受任何类型的数组
如何对任意类型数组中元素进行比较呢?
qsort函数的第4个参数compar:compar是指向一个带两个参数的函数的指针,并以整数的形式返回比较结果。
#include <stdio.h> #include <stdlib.h> int icmp(const void *a,const void *b) { int x = *(int*)a; int y = *(int*)b; if(x==y) return 0; if(x>y) return -1; return 1; }; int main(int argc,char **argv) { int ary[]= {4,7,1,2}; const size_t alen=sizeof(ary)/sizeof(int); size_t i; for(i=0; i<alen; i++) { printf("ary[%d] = %d ",i,ary[i]); } qsort(ary,alen,sizeof(int),icmp); for(i=0; i<alen; i++) { printf("ary[%d] = %d ",i,ary[i]); } }
qsort函数是通过将另一个函数作为参数使用,来实现通用排序功能的。高阶函数这样的方式,通过将一部分处理以函数对象的形式转移到外部,从而实现了算法的通用化。
闭包 《代码的未来》