Rust 对返回值的宏的生存期约束
在以下代码中,Rust 对返回值的宏的生存期约束,rust,macros,lifetime,Rust,Macros,Lifetime,在以下代码中,fun函数和mac宏执行相同的操作: struct S<'s> { src: &'s str, off: usize, } impl std::fmt::Debug for S<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "* {}", &sel
fun
函数和mac
宏执行相同的操作:
struct S<'s> {
src: &'s str,
off: usize,
}
impl std::fmt::Debug for S<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "* {}", &self.src[self.off..])
}
}
fn fun<'s>(value: &'s str) -> S<'s> {
let s = S{ src: value, off: 1 };
s
}
/// The real macro is variadic, that's why it can't be replaced with a function
#[macro_export]
macro_rules! mac {
($value: expr) => {{
let s = S{ src: $value, off: 1 };
// there should be more here
s
}};
}
pub fn main() {
let p = std::path::PathBuf::from("hi");
// works OK
dbg!(fun(&p.to_string_lossy()));
// works ok
let temp = p.to_string_lossy();
dbg!(mac!(&temp));
// can't be compiled
dbg!(mac!(&p.to_string_lossy()));
}
struct S)->std::fmt::Result{
写!(f,“*{}”,和self.src[self.off..)
}
}
fn fun STL;博士
我找到了一个解决方案,灵感来自:
我想我得到了最好的结果:
你需要推荐人吗?一个不理想的解决方案可能是让宏使用p。要使用\u string\u lossy()
@lucidbrot,宏使用一个非常复杂且基于引用的对象(这样它就不会复制东西)。我真的不能改变这个对象,我明白为什么很难。我看到的是一个技巧,使应用于函数调用的生存期规则应用于宏调用。to\u string\u lossy
返回一个Cow
,您希望最后一个示例中的所有者是谁?我明白了。你很清楚这个问题,对吗?使用let
,引用将一直存在,直到main
结束。如果没有,它只存在到宏的末尾,这意味着S
将引用不再存在的内容。事实上,解决方案可能是根据参数的数量使宏调用不同的函数。但这将是一个可怕的宏…这并不像功能解决方案那样符合人体工程学。这是到目前为止我发现的最好的,但我对rust宏没有太多经验。也许你发现了什么better@DenysSéguret请看我的答案的结尾,这是一个允许您返回某些内容的解决方案。它还返回输入表达式,因此它还没有超出范围
#[macro_export]
macro_rules! mag {
($value: expr) => {
($value, S{ src: &$value, off: 1 })
};
}
pub fn main() {
let p = std::path::PathBuf::from("hi");
dbg!(mag!(p.to_string_lossy()).0);
}
struct S<'s> {
src: &'s str,
off: usize,
}
impl std::fmt::Debug for S<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "* {}", &self.src[self.off..])
}
}
fn fun<'s>(value: &'s str) -> S<'s> {
let s = S{ src: value, off: 1 };
s
}
/// The real macro is variadic, that's why it can't be replaced with a function
#[macro_export]
macro_rules! mac {
($value: expr) => {{
let s = S{ src: $value, off: 1 };
// there should be more here
s
}};
}
#[macro_export]
macro_rules! macc {
($value: expr, $var0:ident, $var1:ident) => {
let $var1 = $value;
let $var0 = S{ src: &$var1, off: 1 };
// there should be more here
};
}
pub fn main() {
let p = std::path::PathBuf::from("hi");
// works OK
dbg!(fun(&p.to_string_lossy()));
// works ok
let temp = p.to_string_lossy();
dbg!(mac!(&temp));
// CAN be compiled
macc!(p.to_string_lossy(), alpha, beta);
dbg!(alpha);
}
pub fn main() {
#[macro_export]
macro_rules! maccc {
($value: expr, $var0:ident) => {
let my_own_thing = $value;
let $var0 = S{ src: &my_own_thing, off: 1 };
// there should be more here
};
}
let p = std::path::PathBuf::from("hi");
// works when maccc is defined within the function
maccc!(p.to_string_lossy(), gamma);
dbg!(gamma);
}
struct S<'s> {
src: &'s str,
off: usize,
}
impl std::fmt::Debug for S<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "* {}", &self.src[self.off..])
}
}
#[macro_export]
macro_rules! mag {
($value: expr) => {
($value, S{ src: &$value, off: 1 })
};
}
pub fn main() {
let p = std::path::PathBuf::from("hi");
// works
let (_,m) = mag!(p.to_string_lossy());
dbg!(m);
}
// works
let m = mag!(p.to_string_lossy()).0;
dbg!(m);