如何在不修改函数签名的前提下过滤Rust中msg并修复临时值引用错误
解决方案
核心思路是把过滤后的消息存储在TracingMyLog结构体内部,让debug_args返回的引用指向结构体成员,避免悬垂引用问题,同时不修改原函数签名。
方案1:提前初始化过滤结果
修改结构体新增存储过滤后消息的字段,在结构体创建时完成正则过滤:
use std::collections::HashMap; use regex::Regex; use tracing::Event; pub trait MyLog { fn debug_args(&self) -> &dyn std::fmt::Debug; } // 替换为你项目中实际的Value类型 type Value = String; pub struct TracingMyLog<'a> { record: &'a Event<'a>, fields: HashMap<String, Value>, message: Option<String>, filtered_message: Option<String>, // 新增字段存储过滤后的消息 } impl<'a> TracingMyLog<'a> { pub fn new(record: &'a Event<'a>, fields: HashMap<String, Value>, message: Option<String>) -> Self { // 创建结构体时完成消息过滤 let filtered_message = message.as_ref().map(|msg| { let re = Regex::new(r#"sig: "0x[a-fA-F0-9]+""#).unwrap(); re.replace_all(msg, r#"sig: "***filtered***""#).to_string() }); Self { record, fields, message, filtered_message, } } } impl<'a> MyLog for TracingMyLog<'a> { fn debug_args(&self) -> &dyn std::fmt::Debug { // 直接返回过滤后的消息引用,无消息则返回空字符串引用 self.filtered_message.as_ref().unwrap_or(&"") } }
方案2:延迟初始化过滤结果(按需计算)
如果不想在结构体创建时就执行正则过滤,可以用OnceCell实现延迟初始化,只有第一次调用debug_args时才处理:
use std::collections::HashMap; use std::sync::OnceCell; use regex::Regex; use tracing::Event; pub trait MyLog { fn debug_args(&self) -> &dyn std::fmt::Debug; } type Value = String; pub struct TracingMyLog<'a> { record: &'a Event<'a>, fields: HashMap<String, Value>, message: Option<String>, filtered_message: OnceCell<Option<String>>, // 用OnceCell缓存过滤结果 } impl<'a> MyLog for TracingMyLog<'a> { fn debug_args(&self) -> &dyn std::fmt::Debug { // 首次调用时计算过滤结果,后续直接返回缓存值 let filtered = self.filtered_message.get_or_init(|| { self.message.as_ref().map(|msg| { let re = Regex::new(r#"sig: "0x[a-fA-F0-9]+""#).unwrap(); re.replace_all(msg, r#"sig: "***filtered***""#).to_string() }) }); filtered.as_ref().unwrap_or(&"") } }
原理说明
两种方案都是将过滤后的字符串存储在TracingMyLog结构体内部,debug_args返回的引用生命周期与结构体实例绑定,编译器可保证引用有效性,彻底解决悬垂引用问题,同时完全保留原函数签名。
内容的提问来源于stack exchange,提问作者DiamondDust
相关产品推荐
相关产品推荐

