我想知道是否有什么优雅的解决方案可以让代码/行为与"展开"或"其他"选项类似&lt&T>.我的用例是向函数传递一个可选引用,如果没有使用它,那么创建一个相同类型的默认值来使用.下面是我的代码的简化版本:

#[derive(Debug)]
struct ExpensiveUnclonableThing {}

fn make_the_thing() -> ExpensiveUnclonableThing {
    // making the thing is slow
    // ...
    ExpensiveUnclonableThing {}
}

fn use_the_thing(thing_ref: &ExpensiveUnclonableThing) {
    dbg!(thing_ref);
}

fn use_or_default(thing_ref_opt: Option<&ExpensiveUnclonableThing>) {
    enum MaybeDefaultedRef<'a> {
        Passed(&'a ExpensiveUnclonableThing),
        Defaulted(ExpensiveUnclonableThing),
    }
    let thing_md = match thing_ref_opt {
        Some(thing_ref) => MaybeDefaultedRef::Passed(thing_ref),
        None => MaybeDefaultedRef::Defaulted(make_the_thing()),
    };
    let thing_ref = match &thing_md {
        MaybeDefaultedRef::Passed(thing) => thing,
        MaybeDefaultedRef::Defaulted(thing) => thing,
    };
    use_the_thing(thing_ref);
}

fn use_or_default_nicer(thing_ref_opt: Option<&ExpensiveUnclonableThing>) {
    let thing_ref = thing_ref_opt.unwrap_or_else(|| &make_the_thing());
    use_the_thing(thing_ref);
}

fn main() {
    let thing = make_the_thing();

    use_or_default(Some(&thing));
    use_or_default(None);

    use_or_default_nicer(Some(&thing));
    use_or_default_nicer(None);
}

当unwrap_或_else闭包结束时,这个东西会立即被丢弃,所以我当然会收到一个错误,说明我不能这样做:

error[E0515]: cannot return reference to temporary value
  --> src/main.rs:31:53
   |
31 |     let thing_ref = thing_ref_opt.unwrap_or_else(|| &make_the_thing());
   |                                                     ^----------------
   |                                                     ||
   |                                                     |temporary value created here
   |                                                     returns a reference to data owned by the current function

use_or_default字的"习惯用法"是什么?除了用一些方便的方法创建一个泛型MaybeDefaultedRef<T> type+,还有什么方法可以让它看起来像use_or_default_nicer的实现方式吗?如果有更好的方法,我愿意重构整个过程.

推荐答案

你可以这样写:

fn use_or_default_nicer(thing_ref_opt: Option<&ExpensiveUnclonableThing>) {
    let mut maybe = None;
    let thing_ref = thing_ref_opt.unwrap_or_else(
        || maybe.insert(make_the_thing())
    );
    use_the_thing(thing_ref);
}

也就是说,可以将值本身保留在函数之外,然后在必要时分配给它.不幸的是,一个单位化的值不能被lambda捕获,所以必须将变量设为Option<ExpensiveUnclonableThing>,并用None初始化.

但在我的真实代码中,我也遇到了同样的问题,我写了一本手册match:

fn use_or_default_nicer(thing_ref_opt: Option<&ExpensiveUnclonableThing>) {
    let maybe;
    let thing_ref = match thing_ref_opt {
        Some(x) => x,
        None => {
            maybe = make_the_thing();
            &maybe
        }
    };
    use_the_thing(thing_ref);
}

在我看来,这是更好的,即使再长一点,因为你不需要Option<_>maybe变量是可变的,也不需要假初始化.

有些人在Optionmatch分时会觉得有点失败,认为这是不习惯的,但我并不特别在意.

Rust相关问答推荐

SQL x中的mut *transaction和mut transaction有什么区别?

使用nom将任何空白、制表符、白线等序列替换为单个空白

重新导出proc宏导致未解决的extern crate错误""

为什么单元类型(空元组)实现了`Extend`trait?

使用 struct 外部的属性来改变 struct 的原始方式

这个规则关于或模式到底是什么意思?如果表达片段的类型与p_i|q_i...&q;不一致,就会形成

如何使用syn插入 comments ?

如何用Axum/Tower压缩Html内容?

将一个泛型类型转换为另一个泛型类型

将Vec<;U8&>转换为Vec<;{Float}&>

用于实现获取 struct 体 id 的特征规范

如何轮询 Pin>?

在 Rust 中,为什么 10 个字符的字符串的 size_of_val() 返回 24 个字节?

当没有实际结果时,如何在 Rust 中强制执行错误处理?

Rust并发读写引起的死锁问题

如何将 &[T] 或 Vec<T> 转换为 Arc<Mutex<[T]>>?

不安全块不返回预期值

如何刷新 TcpStream

为什么数组不像向量那样在 for 块之后移动?

我如何将 google_gmail1::Gmail> 传递给线程生成?