当前位置: 首页 > news >正文

浦东网站开发培训江苏网络科技有限公司

浦东网站开发培训,江苏网络科技有限公司,网课营销方案,大连网站推广价格Rust的所有权问题,在我学Rust的时候就跳过了,因为我知道这玩意儿没有场景就不好理解。没想到场景很快就出现了。 在开发Yew应用组件的时候,涉及到了事件,闭包,自然就引出了所有权问题。 话不多说,下面让我们…

Rust的所有权问题,在我学Rust的时候就跳过了,因为我知道这玩意儿没有场景就不好理解。没想到场景很快就出现了。
在开发Yew应用组件的时候,涉及到了事件,闭包,自然就引出了所有权问题。
话不多说,下面让我们直接进入代码场景,去体验并了解Rust的所有权机制吧。

下面这段代码是能够正常工作的。这段代码的逻辑意图也很简单,这是一个函数式的编辑组件,在这个组件中,有一个保存按钮。当用户点击保存按钮时,触发handle_save事件,在handle_save事件中,获取input和textarea的值,并将其通过在Props上定义的on_save Callback,传递给外部组件。

#[function_component(Editor1)]
pub fn editor1(props: &Props) -> Html {let title_ref = use_node_ref();let content_ref = use_node_ref();let Props { on_save, .. } = props;let handle_save = {let title_ref = title_ref.clone();let content_ref = content_ref.clone();let on_save = on_save.clone();Callback::from(move |_| {let title: String = if let Some(title) = title_ref.cast::<HtmlInputElement>() {title.value()} else {"none".to_string()};let content: String = if let Some(content) = content_ref.cast::<HtmlTextAreaElement>() {content.value()} else {"none".to_string()};on_save.emit(EditorData { title, content })})};html! {<div class="editor"><div class="title"><input type="text" ref={title_ref}/><Button text="保存" onclick={handle_save}/></div><div class="content"><textarea value={props.data.content.clone()} ref={content_ref}/></div></div>}
}

Rust的所有权机制最开始虽然不太好理解,但是它的编译器能够在编译时把代码的问题找出来。所以,我们也没有必要抱怨。在Rust中,只要是编译通过的代码都是好代码,哈哈哈。
我们都知道,在不讲所有权机制的编程语言中,变量的使用都比较随意,它们都会被GC或者其它内存管理机制照料。因此,我的第一版代码写出来是这个样子。

#[function_component(Editor1)]
pub fn editor1(props: &Props) -> Html {let title_ref = use_node_ref();let content_ref = use_node_ref();let handle_save = Callback::from(move |_| {let title: String = if let Some(title) = title_ref.cast::<HtmlInputElement>() {title.value()} else {"none".to_string()};});...
}

在这段代码中,直接在闭包中使用了title_ref变量,虽然已经很有Rust的语言特色了,但是还是错了,编译器给出错误提示如下

error[E0382]: use of moved value: `title_ref`--> src/components/editor1.rs:45:41|
31 |     let title_ref = use_node_ref();|         --------- move occurs because `title_ref` has type `yew::NodeRef`, which does not implement the `Copy` trait
...
34 |     let handle_save = Callback::from(move |_| {|                                      -------- value moved into closure here
35 |         let title: String = if let Some(title) = title_ref.cast::<HtmlInputElement>() {|                                                  --------- variable moved due to use in closure
...
45 |                 <input type="text" ref={title_ref}/>|                                         ^^^^^^^^^ value used here after moveFor more information about this error, try `rustc --explain E0382`.

Rust的编译器给我们做了详细的解释,特别的,运行rustc --explain E0382还能看到关于所有权的更加详细的解释。
让我来逐一解读编译器提示及报错,以便让我们更好的了解Rust的所有权机制。

第一个提示

move occurs because `title_ref` has type `yew::NodeRef`, which does not implement the `Copy` trait

title_ref是一个类型为yew::NodeRef且没有实现Copy trait的变量。这里面“没有实现Copy trait”很关键。在我们之前的经历中,遇到Copy trait相关的问题,只需要调用它的.clone()方法就可以解决。如果它没有clone方法,就在它的类型定义上加上#[derive(Clone)]

第二个提示

value moved into closure here

因为有move关键字,因此在闭包中,所有的变量的所有权都会被移动,包括title_ref。问题来了,如果我们把move关键字移除掉,又会是什么提示呢?
让我们开一个小差,把代码修改成下面这个样子。

    let handle_save = Callback::from(|_| {let title: String = if let Some(title) = title_ref.cast::<HtmlInputElement>() {title.value()} else {"none".to_string()};});

编译器的提示和报错如下

error[E0373]: closure may outlive the current function, but it borrows `title_ref`, which is owned by the current function--> src/components/editor1.rs:34:38|
34 |     let handle_save = Callback::from(|_| {|                                      ^^^ may outlive borrowed value `title_ref`
35 |         let title: String = if let Some(title) = title_ref.cast::<HtmlInputElement>() {|                                                  --------- `title_ref` is borrowed here|
note: function requires argument type to outlive `'static`--> src/components/editor1.rs:34:23|
34 |       let handle_save = Callback::from(|_| {|  _______________________^
35 | |         let title: String = if let Some(title) = title_ref.cast::<HtmlInputElement>() {
36 | |             title.value()
37 | |         } else {
38 | |             "none".to_string()
39 | |         };
40 | |     });| |______^
help: to force the closure to take ownership of `title_ref` (and any other referenced variables), use the `move` keyword|
34 |     let handle_save = Callback::from(move |_| {|                                      ++++

这个提示告诉我们,闭包的生命周期可能超出了当前函数的生命周期,但是闭包中借用了title_ref变量。也就是所可能当前函数销毁了,但是闭包还存在。这个时候在闭包中借用title_ref肯定是不合乎逻辑的,因此编译器立即拒绝了这段代码,最后给出了添加move关键字的建议。所以,我们又回到之前的那个讨论。

第三个提示

variable moved due to use in closure

这个提示告诉我们,变量title_ref的所有权被移动是因为这一行代码上使用了该变量。不得不说,这个提示很精确。

第四个报错

value used here after move

这是一个报错信息,在终端上显示的是红色,但是在这里没有把红色显示出来。这个信息告诉我们,title_ref的所有权已经被移动了,不能再使用title_ref了。
这个报错对于从其它开发语言转过来的同学,可能有点匪夷所思。就好像我名下的财产,弄来弄去,最后变成不是我了,我找谁说理去哇。
但这就是Rust的“财产”管理规则。还好它的编译器比较讲道理,把错误(第四)以及这个错误是怎么形成的(第一到第三)都给你说清楚了。
因此,要在闭包中使用title_ref,我们得clone一下。
需要注意的是,如果这个对象已经实现了Copy trait,编译器会自动生成调用copy的代码,就没有必要显示的调用clone()了。但我们的大部分struct只能通过#[derive(Clone)]来实现Clone trait。而通过#[derive(Copy)]来获取Copy trait,大部分情况,由于里面的字段,例如String类型不支持Copy trait,以失败告终。
因此,我们把代码修改成下面这样,就不会报错了。

#[function_component(Editor1)]
pub fn editor1(props: &Props) -> Html {let title_ref = use_node_ref();let content_ref = use_node_ref();let title_ref1 = title_ref.clone();let handle_save = Callback::from(move |_| {let title: String = if let Some(title) = title_ref1.cast::<HtmlInputElement>() {title.value()} else {"none".to_string()};});...}
}

然后,我参考了一下Yew官方的一些例子代码,他们通过block的方式,优雅的处理了这个所有权转移问题(在我看来,至少变量名称干扰少了,但是这种写法,在其它语言中不推荐哇,因为这个是一个赤裸裸的name shadow哇)

    let handle_save = {let title_ref = title_ref.clone();Callback::from(move |_| {let title: String = if let Some(title) = title_ref.cast::<HtmlInputElement>() {title.value()} else {"none".to_string()};})};

好了,关于Rust语言的所有权机制,我暂时就讲到这里,这只是它的冰山一角,希望给大家讲清楚了。听说还有更高级的用法,关于Rc<RefCell<>>或Arc<Mutex<>>,如果后面有遇到,再来和大家分享。

http://www.hyszgw.com/news/61899.html

相关文章:

  • 网站设计影响seo的因素微信管理平台登录
  • 大丰做网站哪家好怎么把自己做的网站
  • 网站没询盘怎么做推广seo快速排名软件易下拉霸屏
  • 公司网站建设提纲wordpress 主题模板下载
  • 建设工程类的网站app网站开发多少钱
  • seo站内优化和站外优化如何做酒店网站
  • 建设国外网站引流吗成立公司注册资金要求
  • 国外免费搭建网站源码做网站选什么主机
  • 做2手物品通过网站去卖掉好做吗竞价推广怎么做
  • 中国建设银行网站怎么登录不上做阿里巴巴网站电话
  • 专业做合同的网站企业网站的宣传功能体现在哪里
  • 电子商务实验网站建设实训过程云上城之歌
  • 技术支持 张家港网站建设深圳市住房建设局网站
  • 英文网站建设方案详细方案369网站建设
  • 英文网站建设电话甘肃网站建站系统平台
  • dz论坛如何做网站地图动态按钮 wordpress插件
  • 广州微信网站建设如何四川德充建设集团有限公司网站
  • 网站内容上传营销推广费计入什么科目
  • 网页网站建设最近发生的新闻事件
  • 廊坊论坛网站建设logo制作下载
  • 做网站怎么搭建环境佛山app平台
  • 购物网站建设特色wordpress 评论后可见
  • 深圳高端品牌网站设计电子商务网站总体规划的内容
  • 网站图片切换怎么做的网站开发基础班内容有哪些
  • 做一个自己的免费网站吗学校网站建设对教学的意义
  • 花瓣是模仿哪个网站wordpress 文章标签 调用
  • 南京自适应网站wordpress js 被改
  • 怎样建立网站目录结构怎么做推广赚钱
  • 建设网站 法律责任公司起名字大全免费测吉凶
  • 1688精品货源网站入口创意网站展示