C++实用指南:Lambda 表达式的妙用

Lambda 表达式的灵活性和强大功能确实为编程提供了许多便利。但是我们发现许多开发者仍然无法灵活运用其便利,于是写了这篇文章。

Lambda 允许我们编写更简洁和灵活的代码。例如在处理网络请求时,我们经常需要确保响应与当前的状态或需求仍然相关。通过捕获上下文变量,Lambda 表达式可以帮助我们在处理异步回调时简化逻辑。

网络请求

案例1:通过捕获 i64RequestIndex 实现丢弃过期的请求回包
在第一个案例中,我们通过捕获请求索引 i64RequestIndex 来确保只处理最新的网络请求。如果请求索引与保存在对象中的最后一个请求索引相匹配,则我们可以确定这是最新的请求,并且可以安全地处理响应。如果索引不匹配,表明在此请求和响应之间,已经发起了新的请求,因此当前的响应已经过时,可以被丢弃。

// 成员变量:用于记录请求序号
int m_myLastRequestIndex = 0;

// 发送网络请求并处理响应
uint64_t i64RequestIndex = ++m_myLastRequestIndex;
core::network::Send(request, [=](Rsp rsp) {
        if (this->m_myLastRequestIndex == i64RequestIndex) {
            // 只处理与最后一次请求索引匹配的响应
        }
    },
    nullptr);

案例2:合并请求以减少后台压力
第一个案例可能会发起很多无效请求。因此,在第二个案例中,我们不仅要检查请求是否为最新的,还需要考虑合并请求。当多个相似的请求在短时间内发起时,我们可以选择等待第一个请求的响应,然后根据需要决定是否发起新的请求。这种方式可以减轻服务器的压力,并提高应用程序的性能。

// 成员变量:用于跟踪是否有正在进行的请求
bool m_isRequestPending = false;
bool m_isNeedNewRequest = false;

// 发起请求的包装函数
auto sendRequest = [&]() {
    m_isRequestPending = true;
    core::network::Send( request, [=](Rsp rsp) {
            m_isRequestPending = false;
            if (m_isNeedNewRequest ) {
                m_isNeedNewRequest  = false;
                sendRequest();// 需要再次发起请求
            } else {
                // 处理最后一次请求的响应
            }
        },
        nullptr);
};

// 逻辑判断是否需要发起请求
if (m_isRequestPending ) {
    // 如果当前已经有一个请求在进行,则等待这个请求的响应
    m_isNeedNewRequest = true;
} else {
    // 如果当前没有请求正在进行,则发起新的请求
    sendRequest();
}

在这个例子中,我们使用一个布尔变量 m_isRequestPending 来跟踪是否有请求正在进行。如果有请求正在进行,我们就等待该请求完成。在请求的回调中,我们将 isRequestPending 设置为 false 以表示请求已完成,并在必要时发起新的请求。

更多场景

1. 延迟执行(Lazy Evaluation)

Lambda 可以用来实现延迟计算,这允许代码仅在需要时才执行相关计算。这在优化性能和资源使用方面非常有用。

auto lazyValue = [expensiveComputation]() { return expensiveComputation(); };
// expensiveComputation 不会立即执行,直到调用 lazyValue()

auto result = lazyValue(); // 在这里实际执行计算

2. 作为回调(Callbacks)

Lambda 经常用作回调函数,尤其是在 GUI 编程或事件驱动编程中。这允许开发者在同一处代码内部即定义事件行为,也提供了更好的上下文管理。

button->onClick([this](){ this->doSomething(); });

3. 作为函数对象(Functors)

Lambda 可以替代传统的函数对象(functors),简化语法并提高代码的可读性。

std::sort(vec.begin(), vec.end(), [](int a, int b) { return a < b; });

4. 作用域保护(Scope Guard)

Lambda 可以用来实现作用域保护模式,确保退出作用域时自动执行特定的清理代码。

auto guard = scope_guard([&] { cleanUpResources(); });

5. 实现装饰器模式(Decorator Pattern)

可以使用 Lambda 表达式来实现装饰器模式,动态地添加功能。

auto withLogging = [](auto func) {
    return [=](auto... args) {
        logBefore(args...);
        auto result = func(args...);
        logAfter(result);
        return result;
    };
};

auto decoratedFunction = withLogging(someFunction);

6. 线程封闭(Thread Encapsulation)

在启动新线程时,Lambda 可以用来封装要在线程中运行的代码,从而使得创建线程的代码更加简洁。

std::thread t([=] { doWork(); });
t.join();

7. 实现状态机(State Machines)

Lambda 可以存储在容器中,使得状态转换和事件处理更加灵活。

std::map<State, std::function<void(Event)>> stateMachine;
stateMachine[State::INIT] = [](Event e) { /* 处理 INIT 状态的事件 */ };

8. 自定义迭代行为(Custom Iteration)

Lambda 可以与算法结合使用,以实现自定义的迭代行为。

std::for_each(collection.begin(), collection.end(), [](auto& item) { processItem(item); });

Lambda 表达式由于其匿名和内联特性,对于创建简洁、灵活的代码非常有用,它们已经成为现代C++编程中不可或缺的工具。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值