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

时间:2018-05-26 14:27:51

标签: rust

我正在使用模拟函数编写测试,使用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()));
    }
}

您可以看到我想要简化的重复块。我创建了一个函数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

请帮我纠正。

1 个答案:

答案 0 :(得分:1)

阅读完整的错误消息:

  

考虑给它一个明确的有界或'静态生命期

这样做有效:

public class A{
    int num;
   public A(){
    }
  public A(int num){this.num = num;}
}

public class B {
 A a;
}

public class Main {
    public static void main(String[] args) {
       B b = new B();
      System.out.println(b.a.num);//Will Throw Null pointer exception if you 
      try to access a,in any case it will not be 0
   }
}
但是,我可能根本不会退回警卫:

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