如何从Arc< dyn RequestInterceptor + Send + Sync >::new()中获取值并将其赋值给rust外部的mut变量?

zfciruhq  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(103)

我尝试使用rust-headless-chrome提取XHR请求的请求URL,使用网络请求拦截方法tab.enable_request_interception(request_interceptor)
错误:

error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
   --> .../extract_xhr_url.rs:64:13
    |
63  |            let request_interceptor: Arc<dyn RequestInterceptor + Send + Sync> = Arc::new(
    |  _______________________________________________________________________________-
64  | |/             move |_transport: Arc<Transport>,
65  | ||                   _session_id: SessionId,
66  | ||                   intercepted_event: RequestPausedEvent| {
    | ||________________________________________________________^ this closure implements `FnMut`, not `Fn`
...   |
85  | |                  xhr_url = request_url.to_owned();
    | |                  --- closure is `FnMut` because it mutates the variable `xhr_url` here
...   |
100 | |              },
101 | |          );
    | |__________- the requirement to implement `Fn` derives from here
    |
    = note: required for `[closure@.../extract_xhr_url.rs:64:13: 66:57]` to implement `RequestInterceptor`
    = note: required for the cast from `[closure@.../extract_xhr_url.rs:64:13: 66:57]` to the object type `dyn RequestInterceptor + Send + Sync`

字符串
代码:

pub fn extract_xhr_url() -> Result<String, Box<dyn Error>> {

    let main_url = "https://website.com".to_owned();
    let mut xhr_url: String;

    let browser = Browser::default()?;
    let tab = browser.new_tab()?;
    let request_pattern = RequestPattern {
        url_pattern: None,
        resource_Type: Some(ResourceType::Xhr),
        request_stage: Some(RequestStage::Request),
    };
    tab.enable_fetch(Some(&[request_pattern]), None)?;
    tab.navigate_to(&main_url)?.wait_until_navigated()?;

    let request_interceptor: Arc<dyn RequestInterceptor + Send + Sync> = Arc::new(
        move |_transport: Arc<Transport>,
              _session_id: SessionId,
              intercepted_event: RequestPausedEvent| {
            let request_url = intercepted_event.params.request.url.as_str();

            xhr_url = request_url.to_owned();

            let continue_request = ContinueRequest {
                request_id: intercepted_event.params.request_id,
                url: Some(intercepted_event.params.request.url.clone()),
                method: Some("GET".to_string()),
                post_data: None,
                headers: None,
                intercept_response: None,
            };
            RequestPausedDecision::Continue(Some(continue_request))
        },
    );

    tab.enable_request_interception(request_interceptor)?;

    Ok(xhr_url)

}


如何将值移出Arc<dyn RequestInterceptor + Send + Sync>并将其重新分配给其作用域之外的可变变量?注意:它不能 Package 在Mutex中,因为tab.enable_request_interception()不能接受Mutex作为它的参数。
有解决办法吗?谢谢你,谢谢
////////////////////////////////////////////////////////////
好吧,按照我尝试使用Arc的建议,编译器诊断程序很安静,但它给出的结果是空的。该值似乎不会传递到闭包之外。此外,控制台在打印闭包内部的值之前打印闭包外部的值。为什么会这样呢?
代码重写:

pub fn extract_xhr_url() -> Result<String, Box<dyn Error>> {

    let main_url = "https://website.com".to_owned();

    // wrap it in Arc<Mutex<String>>
    let xhr_url: Arc<Mutex<String>> = Arc::new(Mutex::new(String::new()));
    // Clone the Arc for use in the closure
    let xhr_url_clone = xhr_url.clone();

    let browser = Browser::default()?;
    let tab = browser.new_tab()?;
    let request_pattern = RequestPattern {
        url_pattern: None,
        resource_Type: Some(ResourceType::Xhr),
        request_stage: Some(RequestStage::Request),
    };
    tab.enable_fetch(Some(&[request_pattern]), None)?;
    tab.navigate_to(&main_url)?.wait_until_navigated()?;

    let request_interceptor: Arc<dyn RequestInterceptor + Send + Sync> = Arc::new(
        move |_transport: Arc<Transport>,
              _session_id: SessionId,
              intercepted_event: RequestPausedEvent| {
            let request_url = intercepted_event.params.request.url.as_str();
            
            // lock it and then assign it a value
            let mut xhr_url = xhr_url_clone.lock().unwrap();
            *xhr_url = new_url.to_owned();
            // prints the value inside of the closure to console
            println!("XHR URL VALUE FROM INSIDE CLOSURE: {}", *xhr_url);

            let continue_request = ContinueRequest {
                request_id: intercepted_event.params.request_id,
                url: Some(intercepted_event.params.request.url.clone()),
                method: Some("GET".to_string()),
                post_data: None,
                headers: None,
                intercept_response: None,
            };
            RequestPausedDecision::Continue(Some(continue_request))
        },
    );

    tab.enable_request_interception(request_interceptor)?;

    // prints the value outside of the closure to console
    println!(
        "XHR URL VALUE FROM OUTSIDE CLOSURE: {}",
        *xhr_url.lock().unwrap()
    );

    Ok(xhr_url)

}


控制台:

XHR URL VALUE FROM OUTSIDE CLOSURE: 
XHR URL VALUE FROM INSIDE CLOSURE: https://another-website.com/foo/bar/barz

mf98qq94

mf98qq941#

您不能从Arc中获取作为可变引用的值。
不过没关系,反正不是你需要的。你真正想做的是将xhr_url Package 在Mutex中(如果存在生存期问题,也可能 Package 在Arc中),这样你就可以在 * 不 * lambda为FnMut的情况下对它进行变异。

相关问题