在Rust中,根据条件高效地重复使用未包装的Option变量。

huangapple go评论59阅读模式
英文:

Efficiently reusing unwrapped Option variable based on a condition in Rust

问题

在Rust中,我有一个名为pbOption变量,我需要在代码的多个部分中使用它。然而,我不想每次访问pb以获取解包后的值时都重复解包的逻辑,当变量progress_bar_ontrue时,我希望pb应该有一个值。是否有一种干净而高效的方法,在代码中解包pb一次,然后在整个代码中使用解包后的值,而不会用重复的匹配语句使代码混乱?

这是一个示例:

// ...

let pb = if progress_bar_on {
  // ...
  Some(tmp_pb)
} else {
  None
}

if progress_bar_on {
  pb.unwrap().update_var();
  pb.unwrap().set_val();
}

// 更多的代码
// ...

if progress_bar_on {
  pb.unwrap().set_val();
}

// 更多的代码
// ...

if progress_bar_on {
  pb.unwrap().update_var();
}

我刚学到的一种感觉更清晰的方法是:

if let Some(pb) =
    progress_bar_on.then(|| pb.unwrap())
{
    pb.set_style(style_overall);
    pb.set_message("Copying files...");
    pb.set_length(src_n_files);
}

这是最干净的方法吗?还有更好的方法吗?
任何见解或建议将不胜感激。谢谢!

英文:

I have an Option variable pb in Rust that I need to use in multiple parts of my code. However, I don't want to repeat the unwrapping logic each time I access pb to obtain the unwrapped value, when I now once the variable progress_var_on is true, pb should have a value. Is there a clean and efficient way to unwrap pb once and use the unwrapped value throughout my code without cluttering it with repeated match statements?

Here is an example:

// ...

let pb = if progress_bar_on {
  // ...
  Some(tmp_pb)
} else {
  None
}

if progress_bar_on {
  pb.unwrap().update_var();
  pb.unwrap().set_val();
}

// more code
// ...

if progress_bar_on {
  pb.unwrap().set_val();
}

// more code
// ...

if progress_bar_on {
  pb.unwrap().update_var();
}

Something I just learn, and it feels cleaner is the next:

if let Some(pb) =
    progress_bar_on.then(|| pb.unwrap())
{
    pb.set_style(style_overall);
    pb.set_message("Copying files...");
    pb.set_length(src_n_files);
}

Is this the cleanest way? or there is a better way?
Any insights or suggestions would be highly appreciated. Thank you!

答案1

得分: 1

你实际上是将布尔值 progress_bar_on 转换为一个 Option,因此你应该使用 Option

if let Some(pb) = pb {
    pb.update_var();
}

然而,这仍然不够清晰,每次使用 pb 时仍然需要进行检查。更健壮的方式是创建一个 trait。

trait ProgressBar: Default {
    fn update_var(&mut self);
    fn set_val(&mut self);
}

#[derive(Default)]
struct RealProgressBar {
    progress: u32,
}

impl ProgressBar for RealProgressBar {
    fn update_var(&mut self) {
        // 一些实际工作
        self.progress += 1;
    }

    fn set_val(&mut self) {
        // 一些实际工作
        self.progress = 0;
    }
}

#[derive(Default)]
struct DummyProgressBar;

// 当用作进度条时,这不会执行任何操作
impl ProgressBar for DummyProgressBar {
    fn update_var(&mut self) {}
    fn set_val(&mut self) {}
}

// 公共函数
pub fn do_operation(progress_bar_on: bool) {
    // 将运行时的布尔值转换为编译时的 trait 实现
    if progress_bar_on {
        do_operation_progress::<RealProgressBar>()
    } else {
        do_operation_progress::<DummyProgressBar>()
    }
}

// 具有所有逻辑的私有函数。它可以无条件地调用进度条上的方法。
fn do_operation_progress<P: ProgressBar>() {
    let mut pb = P::default();

    // 一些代码

    pb.update_var();

    // 更多代码

    pb.set_val();
}
英文:

You're essentially converting the boolean progress_bar_on into an Option, so you should use the Option.

if let Some(pb) = pb {
    pb.update_var();
}

However, this is still not very clean and still has to do a check every time pb will be used. The robust way to is to make a trait.

trait ProgressBar: Default {
    fn update_var(&amp;mut self);
    fn set_val(&amp;mut self);
}

#[derive(Default)]
struct RealProgressBar {
    progress: u32,
}

impl ProgressBar for RealProgressBar {
    fn update_var(&amp;mut self) {
        // Some real work
        self.progress += 1;
    }

    fn set_val(&amp;mut self) {
        // Some real work
        self.progress = 0;
    }
}

#[derive(Default)]
struct DummyProgressBar;

// This does nothing when used as a progress bar
impl ProgressBar for DummyProgressBar {
    fn update_var(&amp;mut self) {}
    fn set_val(&amp;mut self) {}
}

// Public-facing function
pub fn do_operation(progress_bar_on: bool) {
    // Convert the runtime boolean into a compile-time trait impl
    if progress_bar_on {
        do_operation_progress::&lt;RealProgressBar&gt;()
    } else {
        do_operation_progress::&lt;DummyProgressBar&gt;()
    }
}

// Private function that has all the logic. It can unconditionally
// call methods on the progress bar.
fn do_operation_progress&lt;P: ProgressBar&gt;() {
    let mut pb = P::default();

    // some code

    pb.update_var();

    // some more code

    pb.set_val();
}

huangapple
  • 本文由 发表于 2023年5月25日 11:30:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76328747.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定