基于GO语言中的Context思想,C++代码实现框架
·
废话不多说,直接上代码:
#include <iostream>
#include <any>
#include <memory>
#include <string>
#include <unordered_map>
// Context接口定义
class Context {
public:
virtual ~Context() = default;
/**
* 获取与key关联的值,如果不存在则返回空std::any
* 模拟Go中Context的Value方法
*/
virtual std::any Value(const std::any& key) const = 0;
/**
* 便捷方法:尝试将值转换为指定类型,如果失败返回默认值
*/
template<typename T>
T ValueAs(const std::any& key, const T& defaultValue = T{}) const {
std::any result = Value(key);
try {
return std::any_cast<T>(result);
} catch (const std::bad_any_cast&) {
return defaultValue;
}
}
};
// 根Context实现(类似于Go的context.Background())
class BackgroundContext : public Context {
public:
std::any Value(const std::any& key) const override {
return {}; // 根Context不存储任何值
}
std::string String() const { return "BackgroundContext"; }
};
// 存储单个键值对的Context实现
class ValueContext : public Context {
private:
std::shared_ptr<const Context> parent_; // 父Context的共享指针
std::any key_; // 当前Context存储的键
std::any value_; // 当前Context存储的值
public:
/**
* 构造函数:基于父Context创建新的ValueContext
* @param parent 父Context
* @param key 要存储的键
* @param value 要存储的值
*/
ValueContext(std::shared_ptr<const Context> parent, std::any key, std::any value)
: parent_(std::move(parent)), key_(std::move(key)), value_(std::move(value)) {}
std::any Value(const std::any& query_key) const override {
// 比较键的类型和值
if (!key_.has_value() || !query_key.has_value()) {
// 如果任一键为空,继续查找父Context
} else if (key_.type() == query_key.type()) {
// 类型相同,比较值
// 注意:这里简化比较,实际使用时建议使用可比较的类型作为键
try {
// 对于基本类型(int、string等)可以这样比较
if (key_.type() == typeid(int)) {
if (std::any_cast<int>(key_) == std::any_cast<int>(query_key)) {
return value_;
}
} else if (key_.type() == typeid(std::string)) {
if (std::any_cast<std::string>(key_) == std::any_cast<std::string>(query_key)) {
return value_;
}
}
// 可以继续添加其他类型的比较...
} catch (const std::bad_any_cast&) {
// 类型转换失败,继续查找父Context
}
}
// 如果当前Context没有匹配的键,委托给父Context进行链式查找
if (parent_) {
return parent_->Value(query_key);
}
// 整条链都找不到,返回空any
return {};
}
};
// 工厂函数
namespace context {
/**
* 返回一个全局的根Context(类似于Go的context.Background())
*/
std::shared_ptr<const Context> Background() {
static auto bg = std::make_shared<BackgroundContext>();
return bg;
}
/**
* 基于父Context创建新的Context,并存储一个键值对
* 类似于Go的context.WithValue(parent, key, value)
* @param parent 父Context
* @param key 键
* @param value 值
* @return 新的Context共享指针
*/
std::shared_ptr<const Context> WithValue(std::shared_ptr<const Context> parent,
std::any key, std::any value) {
return std::make_shared<ValueContext>(std::move(parent), std::move(key), std::move(value));
}
} // namespace context
// 使用示例和测试函数
void demonstrateBasicUsage() {
std::cout << "=== 基本用法演示 ===" << std::endl;
// 1. 从根Context开始
auto ctx = context::Background();
// 2. 添加用户信息
ctx = context::WithValue(ctx, std::string("user_id"), 1001);
ctx = context::WithValue(ctx, std::string("username"), std::string("Alice"));
ctx = context::WithValue(ctx, std::string("priority"), 5);
// 3. 读取值
int user_id = ctx->ValueAs<std::string, int>("user_id", 0);
std::string username = ctx->ValueAs<std::string, std::string>("username", "unknown");
int priority = ctx->ValueAs<std::string, int>("priority", 1);
std::cout << "用户ID: " << user_id << std::endl;
std::cout << "用户名: " << username << std::endl;
std::cout << "优先级: " << priority << std::endl;
}
void demonstrateChainLookup() {
std::cout << "\n=== 链式查找演示 ===" << std::endl;
// 创建Context链:ctx3 -> ctx2 -> ctx1 -> root
auto ctx1 = context::WithValue(context::Background(), std::string("level"), 1);
auto ctx2 = context::WithValue(ctx1, std::string("level"), 2); // 覆盖level值
auto ctx3 = context::WithValue(ctx2, std::string("data"), std::string("important"));
// ctx3可以访问所有层级的值
int level_from_ctx3 = ctx3->ValueAs<std::string, int>("level", 0);
std::string data = ctx3->ValueAs<std::string, std::string>("data", "");
std::cout << "ctx3中level的值: " << level_from_ctx3 << " (来自ctx2的覆盖)" << std::endl;
std::cout << "ctx3中data的值: " << data << std::endl;
// ctx1只能访问到它和父级的值
int level_from_ctx1 = ctx1->ValueAs<std::string, int>("level", 0);
std::cout << "ctx1中level的值: " << level_from_ctx1 << std::endl;
}
void demonstrateImmutability() {
std::cout << "\n=== 不可变性演示 ===" << std::endl;
auto original = context::WithValue(context::Background(), std::string("version"), 1);
// 基于original创建新的Context,不改变original
auto extended = context::WithValue(original, std::string("stage"), std::string("testing"));
// original看不到新添加的值
auto stage_in_original = original->ValueAs<std::string, std::string>("stage", "not_found");
auto version_in_original = original->ValueAs<std::string, int>("version", 0);
// extended可以看到所有值
auto stage_in_extended = extended->ValueAs<std::string, std::string>("stage", "not_found");
auto version_in_extended = extended->ValueAs<std::string, int>("version", 0);
std::cout << "original中stage: " << stage_in_original << std::endl;
std::cout << "original中version: " << version_in_original << std::endl;
std::cout << "extended中stage: " << stage_in_extended << std::endl;
std::cout << "extended中version: " << version_in_extended << std::endl;
}
// 模拟实际业务场景中的使用
class RequestProcessor {
private:
std::shared_ptr<const Context> ctx_;
public:
RequestProcessor(std::shared_ptr<const Context> ctx) : ctx_(std::move(ctx)) {}
void process() {
// 从Context中获取请求信息
int user_id = ctx_->ValueAs<std::string, int>("user_id", 0);
std::string request_id = ctx_->ValueAs<std::string, std::string>("request_id", "unknown");
std::cout << "处理请求 - 用户ID: " << user_id
<< ", 请求ID: " << request_id << std::endl;
// 在处理过程中可以添加更多信息
auto processing_ctx = context::WithValue(ctx_, std::string("status"), std::string("processing"));
// 传递给下一层处理
validateRequest(processing_ctx);
}
private:
void validateRequest(std::shared_ptr<const Context> ctx) {
std::string request_id = ctx->ValueAs<std::string, std::string>("request_id", "unknown");
std::string status = ctx->ValueAs<std::string, std::string>("status", "unknown");
std::cout << "验证请求 - 请求ID: " << request_id
<< ", 状态: " << status << std::endl;
}
};
void demonstrateRealWorldScenario() {
std::cout << "\n=== 实际业务场景演示 ===" << std::endl;
// 创建包含请求信息的Context
auto ctx = context::Background();
ctx = context::WithValue(ctx, std::string("user_id"), 1001);
ctx = context::WithValue(ctx, std::string("request_id"), std::string("req_abc123"));
ctx = context::WithValue(ctx, std::string("timestamp"), 1637084400);
// 使用Context处理请求
RequestProcessor processor(ctx);
processor.process();
}
int main() {
std::cout << "C++ Context实现 - 模拟Go语言Context的信息传递功能\n" << std::endl;
try {
demonstrateBasicUsage();
demonstrateChainLookup();
demonstrateImmutability();
demonstrateRealWorldScenario();
std::cout << "\n=== 所有演示完成 ===" << std::endl;
} catch (const std::exception& e) {
std::cerr << "发生异常: " << e.what() << std::endl;
return 1;
}
return 0;
}
编译和运行说明
编译命令(需要C++17支持):
g++ -std=c++17 -o context_demo context_demo.cpp
或者使用clang:
clang++ -std=c++17 -o context_demo context_demo.cpp
运行:
./context_demo
核心特性说明
这个实现包含了Go Context的核心思想:
-
链式查找:通过
ValueContext维护父Context的引用,实现递归查找 -
不可变性:每次调用
WithValue都创建新的Context,原Context保持不变 -
类型安全:使用模板方法
ValueAs提供类型安全的访问 -
简单接口:专注于信息传递,去除了复杂的取消机制
关键设计要点
-
使用
std::shared_ptr管理生命周期:确保Context链的正确内存管理 -
std::any存储任意类型:支持灵活的数据存储 -
简单的键比较逻辑:支持基本类型的键比较,可根据需要扩展
更多推荐


所有评论(0)