gpt4 book ai didi

rust - 从函数返回 lazy_static Mutex 的 MutexGuard 需要生命周期参数

转载 作者:行者123 更新时间:2023-11-29 08:18:26 26 4
gpt4 key购买 nike

我正在使用模拟函数编写测试,使用 Mutex 控制测试之间的返回值:

#[macro_use]
extern crate lazy_static;

#[cfg(test)]
pub use mock::*;
#[cfg(not(test))]
pub use real::*;

mod real {
pub fn say_hello(_name: String) -> String {
unimplemented!()
}
}

/// simulate multiple uses, replace `real` in test.
mod mock {
use std::sync::*;
lazy_static! {
pub static ref LOCK: Mutex<bool> = Mutex::new(true);
pub static ref HELLO_VALUE: Mutex<String> = Mutex::new(String::default());
}
pub fn say_hello(_name: String) -> String {
use std::ops::Deref;
HELLO_VALUE.lock().unwrap().deref().clone()
}

pub fn set_hello_return_value(rtn: String) -> MutexGuard<bool> {
let lock = LOCK.lock().unwrap();
let mut value = HELLO_VALUE.lock().unwrap();
*value = rtn;
lock
}
}

#[cfg(test)]
mod test {
use super::*;
#[test]
fn test1() {
// repeated block begin--------------------------
let _lock = LOCK.lock().unwrap();
let mut value = HELLO_VALUE.lock().unwrap();
*value = "Hello Tom!".to_string(); // just this line is different from test2
drop(value);
// repeat block end--------------------------
assert_eq!("Hello Tom!", say_hello("".to_string()));
}

#[test]
fn test2() {
// repeated block begin--------------------------
let _lock = LOCK.lock().unwrap();
let mut value = HELLO_VALUE.lock().unwrap();
*value = "Hello Jack!".to_string(); // just this line is different from test1
drop(value);
// repeat block end--------------------------
assert_eq!("Hello Jack!", say_hello("".to_string()));
}

#[test]
fn test_simplified_but_not_work() {
let _lock = set_hello_return_value("Hello Mark!".to_string());
assert_eq!("Hello Mark!", say_hello("".to_string()));
}
}

您可以看到我要简化的重复 block 。我创建了一个函数 set_hello_return_value 但编译器报错:

error[E0106]: missing lifetime specifier
--> src/main.rs:28:51
|
28 | pub fn set_hello_return_value(rtn: String) -> MutexGuard<bool> {
| ^^^^^^^^^^^^^^^^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
= help: consider giving it an explicit bounded or 'static lifetime

请帮我改正。

最佳答案

阅读完整的错误信息:

consider giving it an explicit bounded or 'static lifetime

这样做有效:

pub fn set_hello_return_value(rtn: String) -> MutexGuard<'static, bool> {
let lock = LOCK.lock().unwrap();
let mut value = HELLO_VALUE.lock().unwrap();
*value = rtn;
lock
}

不过,我可能根本不会还守卫:

pub fn with_hello_return_value<S, F>(rtn: S, f: F)
where
S: Into<String>,
F: FnOnce(),
{
let _lock = LOCK.lock().unwrap();
*HELLO_VALUE.lock().unwrap() = rtn.into();
f()
}

#[test]
fn test_simplified() {
with_hello_return_value("Hello Mark!", || {
assert_eq!("Hello Mark!", say_hello("".to_string()));
});
}

老实说,我不会做任何这样的事情,因为条件编译太过分了。如果您需要单独测试系统的组件,它们不应该相互了解;他们应该依赖注入(inject)。这还有一个额外的好处,即每个测试都可以注入(inject)自己的值,从而保留测试的多线程特性。

fn thing_that_uses_say_hello<G>(greeter: &G, name: &str) -> String
where
G: Greeting,
{
greeter.say_hello(name.into())
}

trait Greeting {
fn say_hello(&self, name: &str) -> String;
}

struct RealGreeting;

impl Greeting for RealGreeting {
fn say_hello(&self, name: &str) -> String {
format!("Hello, {}", name)
}
}

#[cfg(test)]
mod test {
use super::*;
use std::cell::RefCell;

struct MockGreeting<'a> {
called_with: RefCell<Vec<String>>,
value: &'a str,
}

impl<'a> MockGreeting<'a> {
fn new(value: &'a str) -> Self {
Self {
value,
called_with: Default::default(),
}
}
}

impl<'a> Greeting for MockGreeting<'a> {
fn say_hello(&self, name: &str) -> String {
self.called_with.borrow_mut().push(name.to_owned());
self.value.to_owned()
}
}

#[test]
fn test1() {
let g = MockGreeting::new("Hello");
let r = thing_that_uses_say_hello(&g, "Tom");
assert_eq!("Hello", r);
assert_eq!(&*g.called_with.borrow(), &["Tom".to_string()]);
}
}

关于rust - 从函数返回 lazy_static Mutex 的 MutexGuard 需要生命周期参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50543766/

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