我想在返回之前过滤
msg
函数中的 debug_args
:
pub trait MyLog {
fn debug_args(&self) -> &dyn std::fmt::Debug;
}
pub struct TracingMyLog<'a> {
record: &'a tracing::Event<'a>,
fields: Map<String, Value>,
message: Option<String>,
}
impl<'a> MyLog for TracingMyLog<'a> {
fn debug_args(&self) -> &dyn std::fmt::Debug {
if let Some(msg) = self.message.as_ref() {
msg
} else {
&""
}
}
}
我想在 msg 上使用正则表达式,但收到此错误:
cannot return value referencing temporary value returns a value referencing data owned by the current function
。
fn regex_msg(str: &String) -> String {
let re = Regex::new("sig: \"0x[a-fA-F0-9]+\"").unwrap();
re.replace_all(&str, "sig: \"***filtered***\"")
.to_string()
}
fn debug_args(&self) -> &dyn std::fmt::Debug {
if let Some(msg) = self.message.as_ref() {
®ex_msg(msg)
} else {
&""
}
}
我知道这是试图返回对函数本地值的引用,一旦函数返回,其本地值就会被删除,对它们的任何引用都会悬空。
我还尝试在新函数中克隆
msg
字符串并返回对它的引用,这也是编译器不允许的。
最后,我认为
Cow<str>
存在一种解决方法,但我不想使用它。
问。如果可能的话,如何在不改变函数签名的情况下实现上述
msg
的过滤操作?
返回的
&str
总是有生命周期的。因此,如果您想返回引用您在函数中创建的数据的&str
,通常有两种可能性:
self
对象中,并返回生命周期为 &self
的引用。&'static str
。也许您可以在存储消息时应用正则表达式(假设
self.message
是私有字段)?
或者,作为主题的不同变体,您可以将
message
存储为 Option<String>
,而不是 Option<MySecretString>
,直接返回对此的引用,并将正则表达式处理放入 Debug
的
MySecretString
impl 中。我想这就是我会做的。
就我个人而言,这就是我的处理方法:
如果您确实无法更改
debug_args
的签名,那么我会将过滤后的消息存储在结构体的 String
成员中,以便您可以返回对其的引用。然而,MyLog
看起来像是你自己的特质,所以我真的建议你改变它。
我会将
MyLog
更改为如下所示:
pub trait MyLog<'a, T>
where
T: std::fmt::Debug + 'a
{
fn debug_args(&'a self) -> T;
}
这比返回
&dyn Trait
更惯用(它有它的位置,但从我所见这里没有必要)。这基本上是说“你可以实现它来返回任何类型,只要该类型实现 Debug
并且至少与你借用的 &self
一样长”。
然后你可以这样实现:
impl<'a, 'b> MyLog<'a, Cow<'a, str>> for TracingMyLog<'b>
{
fn debug_args(&self) -> Cow<str> {
if let Some(msg) = self.message.as_ref() {
regex_msg(msg)
} else {
"".into()
}
}
}
fn regex_msg(msg: &str) -> Cow<str> {
let re = Regex::new("sig: \"0x[a-fA-F0-9]+\"").unwrap();
re.replace_all(msg, "sig: \"***filtered***\"")
}
这就是说“记录它会返回一个
Cow<str>
:它可能会从 &self
借用一个字符串,也可能不会”。
此外,我还修复了
regex_msg
的签名。首先,你应该总是更喜欢使用 &str
而不是 &String
作为参数(它更灵活,更惯用,而且你很少真正关心数据是否存储在 String
中或者例如文字中) 。其次,它现在像 Cow<str>
一样返回 Regex::replace_all
,避免在未找到匹配项时进行额外分配。最后,请不要命名变量 str
:它可能会让代码的读者感到困惑,因为它是内置类型。
一个稍微简单一点的版本是这样做
pub trait MyLog<T>
where
T: std::fmt::Debug
{
fn debug_args(&self) -> T;
}
但是现在您无法返回
Cow<'_, str>
(因为 &self
和 T
的生命周期之间没有联系),因此您必须 impl MyLog<String>
并仅返回已分配的 String
。为了一些生命周期注释,我认为避免分配是完全值得的。