Rust含双Vec结构体如何实现跨Vec不可变借用?适配nannou回调
解决Nannou框架中结构体引用与生命周期注解的类型不匹配问题
问题背景
定义了如下Rust结构体,意图让Comparison持有Model中recorded_curves元素的引用:
struct Model { recorded_curves: Vec<Curve>, ongoing_comparisons: Vec<Comparison>, } struct Comparison { recording: &Curve, // ... }
添加生命周期注解后,结构体和event函数变为:
struct Comparison<'a> { recording: &'a Curve, // ... } struct Model<'a> { recorded_curves: Vec<Curve>, ongoing_comparisons: Vec<Comparison<'a>>, } fn event<'a>(_app: &App, model: &'a mut Model<'a>, event: Event) { /* ... */ }
但注册event回调时出现类型不匹配错误:
error[E0308]: mismatched types --> src/main.rs:17:30 | 17 | nannou::app(model).event(event).simple_window(view).run(); | ^^^^^ one type is more general than the other | = note: expected fn pointer `for<'r, 's> fn(&'r nannou::App, &'s mut Model<'_>, nannou::Event)` found fn pointer `for<'a, 'r> fn(&'r nannou::App, &'a mut Model<'a>, nannou::Event)`
解决方案
一、无需生命周期注解的实现方式
如果不想处理生命周期,可以通过所有权转移或共享所有权智能指针绕开引用:
1. 让Comparison持有Curve的所有权
如果Curve可以被复制,实现Clone trait后,添加时克隆目标元素:
struct Comparison { recording: Curve, // 持有完整所有权 // ... } // 在event函数中添加实例: model.ongoing_comparisons.push(Comparison { recording: model.recorded_curves[target_index].clone(), // 其他字段初始化 });
2. 使用Arc共享所有权
适合不需要修改Curve的场景,通过Arc实现低成本的共享引用:
use std::sync::Arc; struct Model { recorded_curves: Vec<Arc<Curve>>, ongoing_comparisons: Vec<Comparison>, } struct Comparison { recording: Arc<Curve>, // ... } // 添加时仅克隆Arc指针(无数据拷贝): model.ongoing_comparisons.push(Comparison { recording: Arc::clone(&model.recorded_curves[target_index]), // 其他字段初始化 });
二、修复生命周期注解的正确方式
错误根源是event函数将Model的生命周期与可变引用的生命周期绑定为同一个'a,导致类型不够通用。需要拆分独立的生命周期:
struct Comparison<'a> { recording: &'a Curve, // ... } struct Model<'a> { recorded_curves: Vec<Curve>, ongoing_comparisons: Vec<Comparison<'a>>, } // 拆分两个独立生命周期:'app对应App的引用,'m对应Model的可变引用 fn event<'app, 'm>(_app: &'app App, model: &'m mut Model<'m>, event: Event) { /* ... */ }
更严谨的写法可以显式声明生命周期约束,确保Model的生命周期覆盖可变引用的生命周期:
fn event<'app, 'a, 'm>(_app: &'app App, model: &'m mut Model<'a>, event: Event) where 'a: 'm // 保证Model的生命周期'a长于可变引用的生命周期'm { /* ... */ }
这样就能满足Nannou框架要求的通用函数指针类型。
内容的提问来源于stack exchange,提问作者verified_tinker
相关产品推荐
相关产品推荐

