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);