rust - 为什么分配时会得到 "temporary value dropped while borrowed",但通过函数传递时却不会?

标签 rust borrow-checker ownership borrowing

我对 Rust 很陌生。我主要有 C 和 C++ 方面的经验。

来自 lol_html crate 示例的代码有效。

use lol_html::{element, HtmlRewriter, Settings};

let mut output = vec![];

{
    let mut rewriter = HtmlRewriter::try_new(
        Settings {
            element_content_handlers: vec![
                // Rewrite insecure hyperlinks
                element!("a[href]", |el| {
                    let href = el
                        .get_attribute("href")
                        .unwrap()
                        .replace("http:", "https:");

                    el.set_attribute("href", &href).unwrap();

                    Ok(())
                })
            ],
            ..Settings::default()
        },
        |c: &[u8]| output.extend_from_slice(c)
    ).unwrap();

    rewriter.write(b"<div><a href=").unwrap();
    rewriter.write(b"http://example.com>").unwrap();
    rewriter.write(b"</a></div>").unwrap();
    rewriter.end().unwrap();
}

assert_eq!(
    String::from_utf8(output).unwrap(),
    r#"<div><a href="https://example.com"></a></div>"#
);

但是如果我将 element_content_handlers vec 移到外面并分配它,我会得到

temporary value dropped while borrowed

对于 let 行:

use lol_html::{element, HtmlRewriter, Settings};

let mut output = vec![];

{
    let handlers = vec![
                // Rewrite insecure hyperlinks
                element!("a[href]", |el| {
                    let href = el
                        .get_attribute("href")
                        .unwrap()
                        .replace("http:", "https:");

                    el.set_attribute("href", &href).unwrap();

                    Ok(())
                }) // this element is deemed temporary
            ];

    let mut rewriter = HtmlRewriter::try_new(
        Settings {
            element_content_handlers: handlers,
            ..Settings::default()
        },
        |c: &[u8]| output.extend_from_slice(c)
    ).unwrap();

    rewriter.write(b"<div><a href=").unwrap();
    rewriter.write(b"http://example.com>").unwrap();
    rewriter.write(b"</a></div>").unwrap();
    rewriter.end().unwrap();
}

assert_eq!(
    String::from_utf8(output).unwrap(),
    r#"<div><a href="https://example.com"></a></div>"#
);

我认为该方法拥有向量的所有权,但我不明白为什么它不适用于简单的赋值。我不想先声明所有元素。我希望有一个简单的习惯用法可以让它拥有所有元素。

编辑: 编译器建议将元素绑定(bind)在行前,但是如果我有很多元素怎么办?例如,我想避免命名 50 个元素。有没有办法在不绑定(bind)所有元素的情况下做到这一点?另外为什么临时的生命周期在 vec 内部结束!在 let 绑定(bind)的情况下调用,但当我放置 vec 时则不会调用!在新构造的结构内部传递给方法?最后一个问题对我来说非常重要。

最佳答案

当我第一次尝试重现您的问题时,我发现 try_new 不存在。它在最新版本的 lol_html 中已被删除。将其替换为 new,您的问题没有重现。不过,我能够用 v0.2.0 重现。由于该问题与宏生成的代码有关,因此我尝试了 cargo Expand (您需要安装的东西, see here )。

这是 let handlers = ... 在 v0.2.0 中扩展的内容:

let handlers = <[_]>::into_vec(box [(
    &"a[href]".parse::<::lol_html::Selector>().unwrap(),
    ::lol_html::ElementContentHandlers::default().element(|el| {
        let href = el.get_attribute("href").unwrap().replace("http:", "https:");
        el.set_attribute("href", &href).unwrap();
        Ok(())
    }),
)]);

这是它在 v0.3.0 中扩展的内容

let handlers = <[_]>::into_vec(box [(
    ::std::borrow::Cow::Owned("a[href]".parse::<::lol_html::Selector>().unwrap()),
    ::lol_html::ElementContentHandlers::default().element(|el| {
        let href = el.get_attribute("href").unwrap().replace("http:", "https:");
        el.set_attribute("href", &href).unwrap();
        Ok(())
    }),
)]);

忽略第一行,宏vec就是这样的!扩大。第二行显示了版本生成内容的差异。第一个借用了解析结果,第二个则借用了它的 Cow::Owned 。 (Cow 代表写入时复制,但它对于您想要对借用或拥有的版本进行通用的任何事物更有用。)。

所以简短的答案是宏用于扩展到不被拥有的东西,现在它有了。至于为什么它不需要单独的赋值就能工作,那是因为 Rust 自动为你创建了一个临时变量。

When using a value expression in most place expression contexts, a temporary unnamed memory location is created initialized to that value and the expression evaluates to that location instead, except if promoted to a static

https://doc.rust-lang.org/reference/expressions.html#tempora.. .

最初 rust 为你创建了多个临时变量,所有这些都在相同的范围内有效,即调用 try_new 的范围。当您将向量分解为其自己的分配时,为元素创建的临时值!仅对向量赋值的范围有效。

我看了一下git blame对于元素! lol_html 中的宏,他们做出了更改,因为有人提出了一个本质上与您的问题有关的问题。所以我想说这是一个抽象漏洞中的错误,而不是你对 Rust 的理解的问题。

关于rust - 为什么分配时会得到 "temporary value dropped while borrowed",但通过函数传递时却不会?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64705654/

相关文章:

reference - 我什么时候不应该为引用该特征的实现者而实现该特征?

rust - 我什么时候应该使用 usize vs i32, f32?

rust - Rust 的借用检查器在这里真正提示的是什么?

rust - 代数数据类型的特征

windows - 如何在 Rust 中将图像写入 Windows 剪贴板

rust - 如何分配给匹配分支内的匹配表达式中使用的变量?

reference - 获取&'a T from Option<T<' a>>

c++ - 将 std::unique_ptr 类成员标记为 const

rust - 如何从 rbtree-rs 插入或更新 RBTree?

rust - 修改 HashMap 对象中的特定值,以防以后可以移动其对象的所有权