Rust闭包传递至Mockall时生命周期不匹配问题排查
Mockall中闭包传递给returning方法的生命周期不匹配问题
我在开发《生化危机》模组管理器(命名为REvil)时,尝试通过以下方式将闭包传递给mockall crate的returning方法:
pub fn set_dialog_game_selection(dialogs: &mut Box<MockAsk>, steam_id: String) { dialogs .expect_ask_for_game_decision_if_needed_and_set_game_to_launch() .returning(ask_for_game_decision_if_needed_return_mock(steam_id)); } pub fn ask_for_game_decision_if_needed_return_mock<'x, 'y>( steam_id: String, ) -> Box<dyn Fn(&'x mut REvilConfig, &'y mut REvilManagerState) -> ResultDialogsErr<()> + Send> { let default = move |_: &'x mut REvilConfig, state: &'y mut REvilManagerState| { state.selected_game_to_launch = Some(steam_id.clone()); Ok(()) }; return Box::new(default); }
运行后触发了生命周期不匹配的类型错误:
error[E0308]: mismatched types --> src\tests\integration.rs:128:14 | 128 | .returning(ask_for_game_decision_if_needed_return_mock(steam_id.to_string())); | ^^^^^^^^^ lifetime mismatch | = note: expected associated type `<dyn Fn(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState) -> Result<(), error_stack::Report<DialogsErrors>> + Send as FnOnce<(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState)>>::Output` found associated type `<dyn Fn(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState) -> Result<(), error_stack::Report<DialogsErrors>> + Send as FnOnce<(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState)>>::Output` note: the lifetime requirement is introduced here --> src\dialogs\dialogs.rs:54:10 | 54 | ) -> ResultDialogsErr<()>; | ^^^^^^^^^^^^^^^^^^^^
最终我通过改写代码解决了问题:
pub fn set_dialog_game_selection(dialogs: &mut Box<MockAsk>, steam_id: String) { dialogs .expect_ask_for_game_decision_if_needed_and_set_game_to_launch() .returning(move |_, state| { set_game_decision(steam_id.clone(), state); Ok(()) }); } pub fn set_game_decision(steam_id: String, state: &mut REvilManagerState) { state.selected_game_to_launch = Some(steam_id); }
需要Mock的原函数签名为:
pub type ResultDialogsErr<T> = Result<T, DialogsErrors>; fn ask_for_game_decision_if_needed_and_set_game_to_launch( &mut self, config: &mut REvilConfig, state: &mut REvilManagerState, ) -> ResultDialogsErr<()>;
第一种写法失效的原因
问题出在显式指定的生命周期参数'x和'y上:
- 在
ask_for_game_decision_if_needed_return_mock函数中,你为闭包的参数声明了独立的生命周期'x和'y,这意味着闭包要求传入的两个引用必须分别满足这两个特定的生命周期。 - 但mockall的
returning方法期望的闭包,其参数的生命周期是由mock的函数签名隐式决定的——原函数的两个&mut参数的生命周期是被编译器统一推导的(通常是匿名生命周期,对应调用时的临时生命周期)。 - 你显式指定的
'x和'y与mock期望的隐式生命周期无法匹配,导致编译器抛出类型不匹配错误。
而改写后的代码直接在returning中定义闭包,没有显式指定生命周期,编译器会自动推导闭包参数的生命周期与原mock函数的签名对齐,因此不会出现生命周期冲突。
内容的提问来源于stack exchange,提问作者Lukas Kwiecien
相关产品推荐
相关产品推荐

