refactor: replace unwrap_or with unwrap_or_else for improved error handling (#5163)

In Rust, the `or` and `or_else` methods have distinct behavioral differences. The `or` method always eagerly evaluates its argument and executes any associated function calls. This can lead to unnecessary performance costs—especially in expensive operations like string processing or file handling—and may even trigger unintended side effects.

In contrast, `or_else` evaluates its closure lazily, only when necessary. Introducing a Clippy lint to disallow `or` sacrifices a bit of code simplicity but ensures predictable behavior and enforces lazy evaluation for better performance.
This commit is contained in:
Tunglies
2025-10-22 17:33:55 +08:00
committed by GitHub
parent a05ea64bcd
commit 2d2167e048
18 changed files with 70 additions and 52 deletions

View File

@@ -287,7 +287,7 @@ impl IClashTemp {
}
None => None,
})
.unwrap_or("127.0.0.1:9097".into())
.unwrap_or_else(|| "127.0.0.1:9097".into())
}
pub fn guard_external_controller(config: &Mapping) -> String {

View File

@@ -140,7 +140,7 @@ impl Config {
.latest_ref()
.config
.as_ref()
.ok_or(anyhow!("failed to get runtime config"))?
.ok_or_else(|| anyhow!("failed to get runtime config"))?
.clone();
drop(runtime); // 显式释放锁

View File

@@ -164,8 +164,8 @@ impl PrfItem {
PrfItem::from_url(url, name, desc, item.option).await
}
"local" => {
let name = item.name.unwrap_or("Local File".into());
let desc = item.desc.unwrap_or("".into());
let name = item.name.unwrap_or_else(|| "Local File".into());
let desc = item.desc.unwrap_or_else(|| "".into());
PrfItem::from_local(name, desc, file_data, item.option).await
}
typ => bail!("invalid profile item type \"{typ}\""),
@@ -235,7 +235,7 @@ impl PrfItem {
}),
home: None,
updated: Some(chrono::Local::now().timestamp() as usize),
file_data: Some(file_data.unwrap_or(tmpl::ITEM_LOCAL.into())),
file_data: Some(file_data.unwrap_or_else(|| tmpl::ITEM_LOCAL.into())),
})
}
@@ -331,7 +331,8 @@ impl PrfItem {
}
}
None => Some(
crate::utils::help::get_last_part_and_decode(url).unwrap_or("Remote File".into()),
crate::utils::help::get_last_part_and_decode(url)
.unwrap_or_else(|| "Remote File".into()),
),
};
let update_interval = match update_interval {
@@ -355,7 +356,7 @@ impl PrfItem {
let uid = help::get_uid("R").into();
let file = format!("{uid}.yaml").into();
let name = name.unwrap_or(filename.unwrap_or("Remote File".into()).into());
let name = name.unwrap_or_else(|| filename.unwrap_or_else(|| "Remote File".into()).into());
let data = resp.text_with_charset()?;
// process the charset "UTF-8 with BOM"

View File

@@ -241,8 +241,11 @@ impl IProfiles {
// move the field value after save
if let Some(file_data) = item.file_data.take() {
let file = each.file.take();
let file = file
.unwrap_or(item.file.take().unwrap_or(format!("{}.yaml", &uid).into()));
let file = file.unwrap_or_else(|| {
item.file
.take()
.unwrap_or_else(|| format!("{}.yaml", &uid).into())
});
// the file must exists
each.file = Some(file.clone());

View File

@@ -32,11 +32,11 @@ impl IRuntime {
let patch_tun = patch.get("tun");
if patch_tun.is_some() {
let tun = config.get("tun");
let mut tun: Mapping = tun.map_or(Mapping::new(), |val| {
val.as_mapping().cloned().unwrap_or(Mapping::new())
let mut tun: Mapping = tun.map_or_else(Mapping::new, |val| {
val.as_mapping().cloned().unwrap_or_else(Mapping::new)
});
let patch_tun = patch_tun.map_or(Mapping::new(), |val| {
val.as_mapping().cloned().unwrap_or(Mapping::new())
let patch_tun = patch_tun.map_or_else(Mapping::new, |val| {
val.as_mapping().cloned().unwrap_or_else(Mapping::new)
});
use_keys(&patch_tun).into_iter().for_each(|key| {
if let Some(value) = patch_tun.get(key.as_str()) {