先看一个具体的程序例子,假设我们要实现一个简单的ls命令,它打印出给定目录下的所有文件的文件名。代码如下:
- void ls(char *dir_name){
-
struct dirent * dp;
-
DIR * dirp = opendir(dir_name);
-
if(dirp==NULL) return;
-
while ((dp = readdir(dirp)) != NULL){
-
printf("%s\n",dp->d_name);
-
}
-
closedir(dirp);
-
}
然后在另外一个程序中需要在给定目录下查找以find_str开头,文件大小大于min_byte字节的文件。代码如下:
- void find(char *dir_name, char *find_str, int min_byte){
-
struct dirent * dp;
-
DIR * dirp = opendir(dir_name);
-
if(dirp==NULL) return;
-
while ((dp = readdir(dirp)) != NULL){
-
if(strncmp(dp->d_name, find_str, strlen(find_str))==0){
-
struct stat statbuf;
-
char buf[1024]={0};
-
strcat(buf,dir_name);
-
strcat(buf,dp->d_name);
-
if (stat(buf, &statbuf) !=-1){
-
if(statbuf.st_size>=min_byte) printf("%s, %d\n",dp->d_name, (int)statbuf.st_size);
-
}
-
}
-
}
-
closedir(dirp);
-
}
上面两个代码块中,有很多行代码是重复的。这部分重复的代码用于控制迭代一个目录。一个杰出程序员一定会对这种代码重复深恶痛绝。对这类控制流代码的抽象化就需要闭包来支持了。比如在Ruby中实现类似的功能是很方便的。实现ls的ruby代码如下:
- Dir.open(".").each {|x| puts x}
实现文件名和文件大小查询的ruby代码如下:
- def find(dir,find_str,min_byte)
- Dir.open(dir).each do |x|
- full_path = dir+x
- puts x if x.start_with?(find_str) && File.size(full_path)>min_byte
- end
-
end
如果能够在C语言中实现类似ruby中each方法生活该多美好!
参照ruby的写法,理想的C语言的API如下:
- typedef void (*pDirentVisitor)(struct dirent * dp);
-
-
extern void each(pDirentVisitor visitor, char *dir_name);
其中库作者需要实现each函数,而调用者实现pDirentVisitor函数。
要在C语言中实现这个特性,可以有三种方法:利用GCC的nested function,利用Clang的block,以及自己实现闭包参数传递。这里的难点在于pDirentVisitor函数中要能访问dir_name、find_str、min_byte这些context相关的本地局部变量,这就是闭包的含义。
本文中代码的完整可运行版本放在了Github:
下一篇文章中会讲解如何利用GCC的nest function实现上面的接口。
阅读(2478) | 评论(1) | 转发(1) |