rust - 匹配和解包之间的不同行为

标签 rust error-handling

我做了一个小程序,它显示了一个我无法解释的奇怪行为。
我正在使用 Rodio crate 来尝试一些音频内容。
我做了两个程序,在我看来,应该给出相同的结果。
第一个我使用匹配来处理错误:

let sink : Option<Sink> = match rodio::OutputStream::try_default() {
        Ok((_, handle)) => {
            match Sink::try_new(&handle) {
                Ok(s) => Some(s),
                Err(_e) => None,
            }
        },
        Err(_e) => None,
};
println!("{}", sink.unwrap().len());
在最后一个中,我使用了 unwrap 代替。
let (_, handle) = rodio::OutputStream::try_default().unwrap();
let s = Sink::try_new(&handle).unwrap();
println!("{}",s.len());
第一个按预期执行打印语句,而最后一个在第二个解包中发生 panic 。
只要没有错误传播、隐式转换或其他可以解释的东西,我就很奇怪。这里的问题与错误本身无关,而是与两个代码之间的差异有关。
我将不胜感激任何帮助。

最佳答案

问题是rodio 的范围界定和实现细节之一:这里的一个关键项目是OutputStream::try_default() ,你如何处理并不重要Sink::try_new(&handle)它的行为总是相同的,但并非如此 try_default , 如果您匹配或 if let如果您 unwrap,它会正常工作它会失败。
但为什么会这样,两者应该是等价的。答案就在rodio的细节中,特别是OutputStreamHandle :

pub struct OutputStreamHandle {
    mixer: Weak<DynamicMixerController<f32>>,
}
所以一个 OutputStreamHandle (此后的 OSH)仅对 DynamicMixerController 持有弱引用,其中 OutputStream (此后的操作系统)具有很强的引用值(value)。
这意味着 OSH 仅在操作系统处于事件状态时“工作”。
let (_, handle) = OutputStream::try_default().unwrap();
没有命名操作系统,所以不要捕获它,它立即被删除,Arc被释放,职业安全与卫生没有任何影响,水槽不高兴。
那么另一个如何工作呢?因为
    if let Ok((_, handle)) = OutputStream::try_default() {
        let sink = Sink::try_new(&handle).unwrap();
        println!("match {}", sink.len());
    }
真的是
{
    let _var = OutputStream::try_default();
    if let Ok((_, handle)) = _var {
        let sink = Sink::try_new(&handle).unwrap();
        println!("match {}", sink.len());
    }
}
所以match/if let本身正在保留Result活着,这是一种祝福(但 causes issues just the next question over)。
Result保持事件状态,元组保持事件状态,OutputStream保持活力,Arc保持事件状态,因此 OSH 有一个可用的 mixer ,水槽可以使用。
您可以通过绑定(bind)OutputStream来修复第二个版本的问题。到一个“正确的”名称,例如
let (_stream, handle) = OutputStream::try_default().unwrap();
在名称前加上 _将创建真正的绑定(bind),但会抑制“未使用的变量”警告。
FWIW 小心处理这类事情对于 RAII 类型非常重要,这些类型的值您“不需要”,最常见的是互斥保护代码而不是数据:
let _ = m.lock().unwrap();
什么都不做,互斥锁没有保持事件状态,所以锁被立即释放。在这种情况下,你宁愿
let _lock = m.lock().unwrap():
甚至更好
let lock = m.lock().unwrap();
...
drop(lock);

关于rust - 匹配和解包之间的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69393226/

相关文章:

javascript - 捕获我导出的 async/await 函数的错误

android - SecurityException:无法找到 dex.jar 的字段

hashmap - 为什么使用HashMap的or_insert时会调用闭包?

rust - 如何通过 rust asm 构建屏障?

rust - &[u8] 不能被 RangeFull 索引?

rust - "Sized is not implemented"是什么意思?

linux - 无法加载redis模块,RedisJSON

c# - 在C#异常处理中,有没有一种方法可以检测瞬时错误?

C++ ifstream 错误检查

php - DomDocument验证错误格式