第一章 函数式编程介绍
函数式编程是一种编程范式。在其中,函数是一等公民,函数可以付给其他变量,也可以作为另一个函数的参数或返回值。函数式编程要求,只使用表达式,不使用语句。
函数式编程是声明式的编程,它与命令式编程不同。命令意味着要命令计算机做某事,明确它需要执行的每一步,以计算结果。声明意味着你说明该做什么,然后编程语言的任务是找出如何做,通常它定义是什么,而不是一步一步告诉计算机去执行。
理解命令式和声明式编程的例子
想象一下,你编写一个函数,它接收文件列表并计算每个文件中的行数。
命令式的做法可能会是这样:
- 打开每一个文件
- 定义一个count变量去存储行数
- 每次一个字符一个字符的读文件,当遇到换行符时,count++
- 到了文件末尾,存储count的值
下面是代码:
auto count_lines_in_file(const std::vector<std::string>& files) -> std::vector<int>
{
std::vector<int> result;
int c = 0;
for (const auto& file : files)
{
int count_lines = 0;
std::ifstream in(file);
while (c = in.get())
{
if (c == '\n')
count_lines++;
}
result.push_back(count_lines);
}
return result;
}
但上面的代码易出错,比如未初始化的变量、if、while的条件等等。
下面做法用到了std::count算法和输入流迭代器简化了代码:
int count_lines(const std::string& file)
{
std::ifstream in(file);
// 像对容器一样,也可以对流迭代器使用stl算法
return std::count(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>(), '\n');
}
auto count_lines_in_file(std::vector<std::string>& files) -> std::vector<int>
{
std::vector<int> result;
for (auto& file : files)
{
result.push_back(count_lines(file));
}
}
在上面这个解决方案中,你不用关心count_lines是如何实现的,count_lines只是指出了计算文件的行数。这就是函数式编程的意图。
让我们再次简化代码,接近函数式编程,这次使用了std::transform:
auto coutn_lines_in_file3(std::vector<std::string>& files)
{
std::vector<int> result;
std::transform(files.begin(), files.end(), result.begin(), count_lines);
return result;
}
到了c++20,可以使用范围库再次简化:
auto count_lines_in_file4(std::vector<std::string>& files)
{
// 使用管道操作符(c++20)
return files | std::transform(count_lines);
}