首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >匹配和展开之间的不同行为

匹配和展开之间的不同行为
EN

Stack Overflow用户
提问于 2021-09-30 13:37:19
回答 1查看 138关注 0票数 5

我做了一个小程序,它显示了一个奇怪的行为,我无法解释。我正在使用rodio机箱尝试一些音频的东西。

我做了两个项目,在我看来,应该给出同样的结果。

第一个我使用匹配来处理错误:

代码语言:javascript
复制
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());

在上一篇文章中,我用解包代替了。

代码语言:javascript
复制
let (_, handle) = rodio::OutputStream::try_default().unwrap();
let s = Sink::try_new(&handle).unwrap();
println!("{}",s.len());

第一个按预期执行print语句,而最后一个则在第二个解包装中恐慌。

当没有错误传播、隐式转换或其他可以解释这一点的东西时,我就觉得很奇怪。这里的问题与错误本身无关,而与两种代码之间的差异有关。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-09-30 14:09:17

问题是rodio的范围界定和实现细节:这里的一个关键事项是OutputStream::try_default(),您如何处理Sink::try_new(&handle)并不重要--它的行为总是相同的,而不是try_default,如果匹配或if let,它会很好地工作,如果您unwrap它会失败。

但为什么这两者应该是等同的呢?答案是关于rodio的细节,特别是关于OutputStreamHandle

代码语言:javascript
复制
pub struct OutputStreamHandle {
    mixer: Weak<DynamicMixerController<f32>>,
}

因此,OutputStreamHandle (此后的OSH)只持有对DynamicMixerController的弱引用,而OutputStream (此后的OS)则有很强的引用。

这意味着,只要操作系统还活着,OSH就只能“工作”。

代码语言:javascript
复制
let (_, handle) = OutputStream::try_default().unwrap();

不命名操作系统,所以不保存它,它立即被丢弃,Arc被释放,而OSH什么也没有保存,水槽不快乐。

那另一个怎么能工作呢?因为

代码语言:javascript
复制
    if let Ok((_, handle)) = OutputStream::try_default() {
        let sink = Sink::try_new(&handle).unwrap();
        println!("match {}", sink.len());
    }

真的相当

代码语言:javascript
复制
{
    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,接收器可以利用它。

您可以通过将OutputStream绑定到“适当”名称来解决第二个版本的问题。

代码语言:javascript
复制
let (_stream, handle) = OutputStream::try_default().unwrap();

_作为名称的前缀将为real创建绑定,但会抑制“未使用的变量”警告。

对于RAII类型的值“不需要”(最常见的是互斥保护代码而不是数据),FWIW在这类事情上小心是非常重要的:

代码语言:javascript
复制
let _ = m.lock().unwrap();

不做任何事情,互斥保护没有保持活着,所以锁立即释放。在这种情况下,你宁愿

代码语言:javascript
复制
let _lock = m.lock().unwrap():

甚至更好

代码语言:javascript
复制
let lock = m.lock().unwrap();
...
drop(lock);
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69393226

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档