3

我正在使用 Rust 和 Rocket 构建 REST API。我有一个端点,在该端点上创建一个新用户,定义如下:

/// View with which to create a user
#[post("/users", format = "application/json", data = "<user_data>")]
fn create_user(user_data: Json<UserData>, db: DB) -> Status<Json<Value>> {
    let conn = db.conn();
    let _new_user_result = user_data.into_new_user(&conn);
    unimplemented!()
}

注意这里没有借用的内容;两者user_datadb拥有。不过,我在编译时收到以下错误:

error[E0507]: cannot move out of borrowed content
  --> src/views/user_account.rs:75:28
   |
75 |     let _new_user_result = user_data.into_new_user(&conn);
   |                            ^^^^^^^^^ cannot move out of borrowed content

作为参考,函数签名into_new_user

fn into_new_user(self, conn: &SqliteConnection) -> Result<NewUser, Status<Json<Value>>> {
    ...
}

这里发生了什么?如果我真的借了任何东西,这个错误会更容易理解,但考虑到我拥有所有有问题的东西,我很困惑。

$ rustc --version; cargo --version
rustc 1.22.0-nightly (a47c9f870 2017-10-11)
cargo 0.23.0-nightly (e447ac7e9 2017-09-27)
4

1 回答 1

7

这里的问题在于user_data. 具体来说,正如函数签名中所写的那样,它的类型是Json<UserData>.

Json<T>是一个包装器类型,它告诉 Rocket 如何包装和解包 JSON 值;这是一种包装结构的便捷方法,但不存储任何额外数据。因此,它实现Deref<Target = T>了 ,这让您几乎可以忽略它。但是,这仅在您不尝试使用它时才有效。

实现的类型通常Deref<Target=T>可以像使用;一样使用。编译器为您处理间接。但是,该函数调用中实际发生的事情更像是,这就是问题发生的地方:被定义为. 借用是隐含的、不可见的,但它就在那里。T<Json<UserData> as Deref<Target=UserData>>::deref().into_new_user();dereffn deref(&self) -> &Self::Target

在这种Json情况下,类型不再是必需的;它只是用来反序列化UserData结构。因此,我们可以通过丢弃它来解决问题。该Json::into_inner方法丢弃Json包装器,给你一个拥有的UserData. 然后可以按计划消费。放在一起,函数应该是这样的:

fn create_user(user_data: Json<UserData>, db: DB) -> Status<Json<Value>> {
    let conn = db.conn();
    let _new_user_result = user_data.into_inner().into_new_user(&conn);
    unimplemented!()
}
于 2017-10-24T10:51:33.163 回答