rust - 如果我分配,为什么我得到“借用时临时价值下降”,但在通过函数传递时却没有?
问题描述
我对 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 移到外面并分配它,我会得到
借入时临时价值下降
对于 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>"#
);
我认为该方法拥有向量的所有权,但我不明白为什么它不适用于简单的分配。我不想先声明所有元素。我希望有一个简单的成语让它拥有所有元素。
编辑:编译器建议在行之前绑定元素,但是如果我有很多元素怎么办?例如,我想避免命名 50 个元素。有没有办法在不绑定所有元素的情况下做到这一点?还有为什么临时的生命周期在 vec 内部结束!在 let 绑定的情况下调用,但不是在我放置 vec 时调用!在新构造的结构内部传递给一个方法?最后一个问题对我来说很重要。
解决方案
当我第一次尝试重现您的问题时,我发现它try_new
不存在。它已在最新版本的 lol_html 中被删除。用 替换它new
,您的问题没有重现。不过,我能够使用 v0.2.0 进行复制。由于该问题与宏生成的代码有关,因此我尝试cargo expand
了(您需要安装的东西,请参见此处)。
这是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的宏是怎么回事!展开。第二行显示了版本生成的差异。第一个借用 parse 的结果,第二个取一个 Cow::Owned 。(Cow 代表写时复制,但它更普遍地适用于任何你想要通用的东西,而不是借来的或拥有的东西。)。
因此,简短的回答是用于扩展为不属于自己的东西的宏,现在它可以了。至于为什么不用单独赋值就可以工作,那是因为 Rust 自动为你创建了一个临时变量。
在大多数位置表达式上下文中使用值表达式时,会创建一个临时的未命名内存位置,并初始化为该值,并且表达式将计算到该位置,除非提升为静态
https://doc.rust-lang.org/reference/expressions.html#tempora ..。
最初 rust 为您创建了多个临时对象,所有这些都对相同的范围有效,即调用 try_new 的范围。当您将向量分解为自己的分配时,将为元素创建临时!仅对向量赋值的范围有效。
我查看了元素的git blame !lol_html 中的宏,他们做出了改变,因为有人提出了一个本质上是你的问题的问题。所以我会说这是一个泄漏抽象中的错误,而不是您对生锈的理解的问题。
推荐阅读
- amazon-web-services - 如何限制访问特定的 ssm 文档只能在特定的 ec2 实例中运行?
- doxygen - 如何在 doxygen 中记录外部文件?
- python - 使用 changelist_view 在 django admin 中重定向
- javascript - 将捕获的图像保存到 react-native 中的自定义秘密相册
- c# - 项目启动时的 System.InvalidOperationException
- laravel - laravel JSON 验证规则
- git - 是否有任何 git 目录可以在默认情况下绝对且始终被忽略?
- python-3.x - Python:将列表中的子元素打印到 CSV
- npm - 带有 Webpack 的 MapboxGL:“ReferenceError: e is not defined”(在 vue-cli 应用程序中)
- python - 通过 Python 读取 txt 文件时的编解码器问题