gpt4 book ai didi

rust - 返回值的宏的生命周期约束

转载 作者:行者123 更新时间:2023-12-05 01:28:35 33 4
gpt4 key购买 nike

在下面的代码中,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()));
}

但是调用宏就没那么容易了。最后一行代码无法编译。

我如何修复宏以避免“仍在使用时释放的临时变量”问题,以便宏用户不必创建无用的冗长临时变量?

playground

最佳答案

长话短说

#[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);
}

我找到了一个解决方案,灵感来自 this Answer :

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

我定义了一个宏 macc 而不是你的 mac。它需要一些标识符,然后在您的调用范围内可用(即在 main() 内)。
这样,宏就可以让 beta 保持在范围内。这样宏就不会创建意外的标识符,覆盖现有的变量名。

playground


如果宏是defined within the same function ,您可以摆脱两个标识符参数之一:

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

我想我已经做到了:

playground

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

这将返回一个包含临时值和 s 的元组,因此临时值不会超出范围。您甚至可以这样做:

   // works
let m = mag!(p.to_string_lossy()).0;
dbg!(m);

关于rust - 返回值的宏的生命周期约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59306592/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com