我如何避免在此代码中使用全局可变变量?

How might I avoid a global mutable variable in this code?

如果在 this website 上找到某个 div,以下代码将打印 There is page two.

use reqwest;
use select::document::Document;
use select::predicate::Name;
use std::io;

static mut DECIDE: bool = false;

fn page_two_filter(x: &str, url: &str) {
    if x == "pSiguiente('?pagina=2')" {
        unsafe {
            DECIDE = true;
        }
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Give me the URL with the search results?");
    let mut url = String::new();
    io::stdin()
        .read_line(&mut url)
        .expect("Failed to read line");

    let url = url.trim();
    let html = reqwest::get(url).await?.text().await?;

    Document::from(html.as_str())
        .find(Name("div"))
        .filter_map(|n| n.attr("onclick"))
        .for_each(|x| page_two_filter(x, url));
    unsafe {
        if DECIDE == true {
            println!("There is page two.")
        }
    }
    Ok(())
}

来自 Cargo.toml

的依赖项
[dependencies]
futures = "0.3.15"
reqwest = "0.11.9"
scraper = "0.12.0"
select = "0.5.0"
tokio = { version = "1", features = ["full"] }

是否有更安全的方法,即没有 unsafe 代码块来执行该代码的操作? 为了避免全局可变变量,我尝试重新定义 page_two_filter 和一个带有调用 page_two_filter 结果的 if 语句,如下所示:

fn page_two_filter(x: &str, url: &str) -> bool {
    if x == "pSiguiente('?pagina=2')" {
        return true;
    }
    false
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Give me the URL with the search results?");
    let mut url = String::new();
    io::stdin()
        .read_line(&mut url)
        .expect("Failed to read line");

    let url = url.trim();
    let html = reqwest::get(url).await?.text().await?;
    if Document::from(html.as_str())
        .find(Name("div"))
        .filter_map(|n| n.attr("onclick"))
        .for_each(|x| page_two_filter(x, url))
    {
        println!("There is page two.")
    }
    Ok(())
}

但是编译器不允许我这样做说:

mismatched types expected `()`, found `bool`

而不是 for_each(),我猜你需要 find()

这个 returns Some( found_element ) 如果找到或 None 如果没有找到。

然后您可以将 find() 返回的 Optionif letmatchis_some()...

一起使用
    if let Some(_) = Document::from(html.as_str())
        .find(Name("div"))
        .filter_map(|n| n.attr("onclick"))
        .find(|x| page_two_filter(x, url))
    {
        println!("There is page two.")
    }

首先,

mismatched types expected (), found bool

错误是因为for_each闭包中println语句后没有分号

其次,过滤器实际上是一个 one-liner,它可以集成在那个闭包中

fn page_two_filter(x: &str, url: &str) -> bool {
  x == "pSiguiente('?pagina=2')"
}

最后,您已经使用了各种迭代器方法,为什么不继续呢?

async fn main() -> Result<(), Box<dyn std::error::Error>> {
 println!("Give me the URL with the search results?");  
 let mut url = String::new();
 io::stdin().read_line(&mut url).expect("Failed to read line");
 
 let url = url.trim();
 let html = reqwest::get(url).await?.text().await?;
 if let Some(_) = Document::from(html.as_str())
    .find(Name("div"))
    .filter_map(|n| n.attr("onclick"))
    .find_map(|attr| if attr == "pSiguiente('?pagina=2')" {
        Some(true)
    } else {
        None
    }) {
    
        println!("There is page two.");
    }

    Ok(())

}

您可以在第一次找到条件时使用 Iterator::any which returns true,否则 false

fn page_two_filter(x: &str, url: &str) -> bool {
    x == "pSiguiente('?pagina=2')"
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Give me the URL with the search results?");
    let mut url = String::new();
    io::stdin()
        .read_line(&mut url)
        .expect("Failed to read line");

    let url = url.trim();
    let html = reqwest::get(url).await?.text().await?;

    let found = Document::from(html.as_str())
        .find(Name("div"))
        .filter_map(|n| n.attr("onclick"))
        .any(|x| page_two_filter(x, url));

    if found {
        println!("There is page two.");
    }
}