让我们来讨论迭代器,这是一个非常有用的工具,在整个EOS代码库中都被大量使用。如果您处于JavaScript的背景下,您可能已经熟悉迭代器,就像循环中使用的迭代器一样。迭代器的关键概念是提供一种更好的遍历项集合的方法。额外的好处是,您可以为任何定制类实现迭代器接口,使迭代器成为遍历数据的通用方法。
// @url: https://repl.it/@MrToph/CPPBasics-Iterators
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v{2, 3, 5, 8};
// old way to iterate
for (int i = 0; i < v.size(); i++)
{
cout << v[i] << "\n";
}
// using Iterators
// begin() returns an iterator that points to the beginning of the vector
// end() points to the end, can be compared using != operator
// iterators are incremented by using the + operator thanks to operator-overloading
for (vector<int>::iterator i = v.begin(); i != v.end(); i++)
{
// iterators are dereferenced by * like pointers
// returns the element the iterator is currently pointing to
cout << *i << "\n";
}
// auto keyword allows you to not write the type yourself
// instead C++ infers it from the return type of v.begin
for (auto i = v.begin(); i != v.end(); i++)
{
cout << *i << "\n";
}
// can use arithmetic to "jump" to certain elements
int thirdElement = *(v.begin() + 2);
cout << "Third: " << thirdElement << "\n";
// end is the iterator that points to the "past-the-end" element
// The past-the-end element is the theoretical element that would follow the last element in the vector.
// It does not point to any element, and thus shall not be dereferenced.
int lastElement = *(v.end() - 1);
cout << "Last: " << lastElement << "\n";
// do not go out of bounds by iterating past the end() iterator
// the behavior is undefined
// BAD: v.end() + 1, v.begin() + 10
}
在现代c++中,迭代器是迭代元素集合(向量、列表、映射)的首选方法。另外,可以避免键入冗长的类型,但可能会导致缺乏表现力的代码。
Lambda表达式
有了迭代器,我们可以开始研究现代c++的函数式编程概念。标准库中的许多函数都将由两个迭代器(开始和结束)和一个匿名函数(lambda函数)表示的元素范围作为参数。然后将这个匿名函数应用于范围内的每个元素。它们之所以被称为匿名函数,是因为它们不绑定到变量,而是绑定于短逻辑块中,作为内联参数传递给高阶函数。通常,它们对于传递给它们的函数是唯一的,因此不需要拥有名称。
有了它,我们可以实现类似于排序、映射、过滤等结构,这些结构在JavaScript等语言中很容易实现:
[1,2,3,4].map(x => x*x).filter(x => x % 2 === 1).sort((a,b) => b - a)
c++中的代码并不简洁,但是结构是一样的。STD库中的许多函数式编程助手都是在半开区间上操作的,这意味着包含了较低的区间,而排除了较高的区间。
// @url: https://repl.it/@MrToph/CPPBasics-Lambdas
#include <iostream>
#include <vector>
// for sort, map, etc.
#include <algorithm>
using namespace std;
int main()
{
vector<int> v{2, 1, 4, 3, 6, 5};
// first two arguments are the range
// v.begin() is included up until v.end() (excluded)
// sorts ascending
sort(v.begin(), v.end());
// in C++, functions like sort mutate the container (in contrast to immutability and returning new arrays in other languages)
for (auto i = v.begin(); i != v.end(); i++)
{
cout << *i << "\n";
}
// sort it again in descending order
// third argument is a lambda function which is used as the comparison for the sort
sort(v.begin(), v.end(), [](int a, int b) { return a > b; });