rust - 一个结构域的析构函数依赖于另一个结构域而没有任何关联

标签 rust lifetime

我试图提供一个简短的可复制示例,但无法重现我的问题,因此我从主要代码中剥离了大部分内容,从而保留了该错误。
lib.rs

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::{quote};
use syn::{
    parse_macro_input, Data, DeriveInput, Field, Fields, Ident,
    Type, TypeGenerics,
};

struct IterMapped<Ret, T: Iterator + Clone> {
    iter: T,
    map_func: Box<dyn FnMut(T::Item) -> Ret>,
}

impl<Ret, T: Iterator + Clone> IterMapped<Ret, T> {
    pub fn new(iter: T, map_func: Box<dyn FnMut(T::Item) -> Ret>) -> Self {
        IterMapped { iter, map_func }
    }
}

enum BuilderField<'a> {
    Optional(&'a Field, &'a Type),
    Mandatory(&'a Field),
}

struct BuilderData<'a> {
    struct_name: &'a Ident,
    builder_struct_name: &'a Ident,
    ty_generics: &'a TypeGenerics<'a>,
    fields_mapped_iter: IterMapped<BuilderField<'a>, syn::punctuated::Iter<'a, Field>>,
}

#[proc_macro_derive(Builder)]
pub fn derive(input: TokenStream) -> TokenStream {
    let derive_input = parse_macro_input!(input as DeriveInput);

    let data = &derive_input.data;
 
    let struct_name = &derive_input.ident;
    let (impl_generics, ty_generics_temp, where_clause) = derive_input.generics.split_for_impl();
 
    let fields_iter = match data {
        Data::Struct(ref data_struct) => match data_struct.fields {
            Fields::Named(ref fields_named) => fields_named.named.iter(),
            Fields::Unnamed(_) | Fields::Unit => {
                panic!()
            }
        },
        _ => panic!()
    };
 
    let fields_mapped_iter = IterMapped::new(
        fields_iter,
        Box::new(|field| BuilderField::Mandatory(field)),
    );

    let ref ty_generics = ty_generics_temp;
    let ref builder_struct_name = Ident::new(
        &format!("{}Builder", struct_name),
        proc_macro2::Span::call_site(),
    );

    let mut builder_data = BuilderData {
        struct_name,
        builder_struct_name,
        ty_generics,
        fields_mapped_iter,
    };

    TokenStream::from(quote!())
}
Cargo.toml
[package]
name = "derive_builder"
version = "0.0.0"
edition = "2018"
autotests = false
publish = false

[lib]
proc-macro = true

[dependencies]
syn = "1.0.48"
quote = "1.0.7"
proc-macro2 = "1.0.24"
运行它会产生以下错误:
error[E0716]: temporary value dropped while borrowed
  --> builder/src/lib.rs:58:35
   |
58 |       let ref builder_struct_name = Ident::new(
   |  ___________________________________^
59 | |         &format!("{}Builder", struct_name),
60 | |         proc_macro2::Span::call_site(),
61 | |     );
   | |_____^ creates a temporary which is freed while still in use
...
71 |   }
   |   -
   |   |
   |   temporary value is freed at the end of this statement
   |   borrow might be used here, when `fields_mapped_iter` is dropped and runs the destructor for type `IterMapped<BuilderField<'_>, syn::punctuated::Iter<'_, syn::data::Field>>`
   |
   = note: consider using a `let` binding to create a longer lived value
我不明白为什么要删除builder_struct_name的临时效果fields_mapped_iter。这两个是单独的字段。
如果我将BuilderData更改为使用生存期'b,则代码可以编译并正常工作:
struct BuilderData<'a, 'b> {
    struct_name: &'a Ident,
    builder_struct_name: &'a Ident,
    ty_generics: &'a TypeGenerics<'a>,
    fields_mapped_iter: IterMapped<BuilderField<'b>, syn::punctuated::Iter<'b, Field>>,
}
☝️将BuilderData更改为此可以使代码正常工作。
如果我重新排列结构字段的声明顺序,并在设置let ref builder_struct_name = …fields_iter之前移动fields_mapped_iter,它会起作用,因为然后将这2个放在builder_struct_name的温度之前。为什么他们的析构函数依赖builder_struct_name的temp?

最佳答案

当作用域结束时,将以与声明变量相反的顺序删除变量。因此,BuilderData的生存期参数'a不能超出将builder_struct_name降低到fields_mapped_iter的整个使用生命周期时的范围。但是, syn::punctuated::Iter
要求其类型参数T的生命周期超过其
生存期参数'a

关于rust - 一个结构域的析构函数依赖于另一个结构域而没有任何关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64769867/

相关文章:

sorting - 使用多个键排序时反转特定键

.net - Windows Phone 8 应用程序生命周期事件和异步/等待

rust - 值(value)活得不够长

rust - 为什么不能在同一结构中存储值和对该值的引用?

rust - 在包含动态大小数组的缓冲区上创建结构 "view"

Rust 正确的错误处理(自动从一种错误类型转换为另一种带有问号的错误类型)

rust - 为什么 impl trait 不能用于返回多个/条件类型?

python - 如何使用Python中的lifetimes包获取客户生命周期的期望值

rust - 谁借用了一个变量?

expression - 是println!表达或陈述?