循环遍历一个容器的数据的时候,我们都会使用foreach的语法,或者类似python/rust语言中的for xxx in container的语法,这样用起来非常爽。由于我在obotcha里面自己实现了ArrayList等容器,每次遍历都需要用比较繁琐的iterator,代码如下:
auto ite = list->getIterator();
while(ite->hasValue()) {
xxxxx;
ite->next();
}
虽然逻辑上没有错误,但是整体代码看上去有很多重复代码,有点不舒服。所以想起了是不是可以实现类似的foreach语法。为了区别于foreach,我们在Obotcha里面定义了一个ForEveryOne的宏定义。具体使用如下:
ForEveryOne(value,list) {
xxxxxx
}
粗粗看起来,是不是和foreach基本一样啦?哈哈,对比使用iterator的代码,是不是简单了很多?
关键ForEveryOne还支持并发操作,也就是说大括号里面的代码是线程安全的~。好的,现在我们看一下这个ForEveryOne的实现原理吧~
#define ForEveryOne(X,Y) \
auto X##__m_lock = __forEveryOneAcquireLock(Y);\
decltype(Y->getIterator()) X##__iterator;\
decltype(X##__iterator->getItem()) X;\
auto X##_Func = ([&X##__iterator,&X](decltype(Y) &container)->decltype(true){\
if(X##__iterator == nullptr){\
X##__iterator = container->getIterator();\
if(!X##__iterator->hasValue()) {\
return false;\
}\
}\
if(X##__iterator->hasValue()) {\
X = X##__iterator->getItem();\
}\
return true;\
});\
for(AutoLock X##__forEveryOne_l(X##__m_lock);\
X##_Func(Y) && X##__iterator->hasValue();\
X##__iterator->next())
1.获取当前容器的读锁
auto X##__m_lock = __forEveryOneAcquireLock(Y);\
2.获取当前容器的迭代器
decltype(Y->getIterator()) X##__iterator;\
3.定义一个获取容器数据的变量
decltype(X##__iterator->getItem()) X;\
4.定义一个lambda函数,用来获取当前的容器的数据
auto X##_Func = ([&X##__iterator,&X](decltype(Y) &container)->decltype(true){\
if(X##__iterator == nullptr){\
X##__iterator = container->getIterator();\
if(!X##__iterator->hasValue()) {\
return false;\
}\
}\
if(X##__iterator->hasValue()) {\
X = X##__iterator->getItem();\
}\
return true;\
});\
5.记下来就是一个for循环,第一个表达式里面我们初始化了一个AutoLock,这样就能确保遍历concurrentQueue这类的容器时线程安全。如果是遍历ArrayList这类非线程安全的容器,起始这个AutoLock是没有效果的。
for(AutoLock X##__forEveryOne_l(X##__m_lock);\
第二个表达式
X##_Func(Y) && X##__iterator->hasValue();\
这个主要就是判断是否还有数据,X##_Func(Y)这个是【4】定义的lambda函数,主要做取值的操作。
第三个表达式就很简单了:
X##__iterator->next()
这样就能简单的实现一个自己的foreach函数了~。哈哈。
大家要是感兴趣的话,可以看一下obotcha的github