如何在Rust中反序列化JSON响应而不移动响应对象?

bq8i3lrv  于 2023-05-22  发布在  其他
关注(0)|答案(1)|浏览(179)

Context

我正在构建一个小型的Rust CLI来自动化Gitlab中的一些任务。我使用reqwest将我的HTTP请求发送到Gitlab API。我目前正在重构我的代码,现在我想删除这个重复的代码段。

fn main() {
    // ... some code
    let create_branch_response = gitlab::create_branch(&client, &args)
        .expect("An error ocurred while processing your request to create a new branch");
    match create_branch_response.status() {
        StatusCode::OK => (),
        StatusCode::BAD_REQUEST => {
            let json_response = create_branch_response
                .json::<gitlab::GitlabError>()
                .expect("An unkown error happened while creating your new branch!");
            panic!(
                "A validation error ocurred while creating your new branch: {}",
                json_response.message
            );
        }
        _ => panic!("An unexpected error ocurred while creating your new branch"),
    }
    let new_branch = create_branch_response
        .json::<gitlab::Branch>()
        .expect("An error ocurred while reading the response");
    println!("New branch {} created!", new_branch.name);
    println!("URL: {}", new_branch.web_url);
    // Some other code
    let create_pr_response = gitlab::create_pr(&client, &args)
        .expect("An error ocurred while processing your request to create a merge request");
    match create_pr_response.status() {
        StatusCode::OK => (),
        StatusCode::BAD_REQUEST => {
            let json_response = create_pr_response
                .json::<gitlab::GitlabError>()
                .expect("An unkown error happened while creating your new merge request!");
            panic!(
                "A validation error ocurred while creating your new merge request: {}",
                json_response.message
            );
        }
        _ => panic!("An unexpected error ocurred while creating your merge request"),
    }
    let new_pr = create_pr_response
        .json::<gitlab::MergeRequest>()
        .expect("An error ocurred while reading the merge request response");
    println!("New pull request \"{}\" created!", new_pr.title);
    println!("URL: {}", new_pr.web_url);
}

我的目标是在一个单独的函数上处理响应的状态码:

pub fn handle_response_status(status: StatusCode, resource: String, response: &Response) {
    match status {
        StatusCode::OK => (),
        StatusCode::BAD_REQUEST => {
            let json_response = response.json::<gitlab::GitlabError>().expect(
                format!(
                    "An unkown error happened while creating your new {}!",
                    resource
                )
                .as_str(),
            );
            panic!(
                "A validation error ocurred while creating your new {}: {}",
                resource, json_response.message
            );
        }
        _ => panic!(
            "An unexpected error ocurred while creating your {}",
            resource
        ),
    }
}

由于json方法调用将我的响应体反序列化为所需的结构体,因此此代码无法工作。

error[E0507]: cannot move out of `*response` which is behind a shared reference
  --> src/util.rs:22:33
   |
22 |             let json_response = response.json::<gitlab::GitlabError>().expect(
   |                                 ^^^^^^^^^-----------------------------
   |                                 |        |
   |                                 |        `*response` moved due to this method call
   |                                 move occurs because `*response` has type `reqwest::blocking::Response`, which does not implement the `Copy` trait

我所尝试的

我已经尝试了以下方法(对不起,我对生 rust 还是新手)。

let json_response = response.clone().json::<gitlab::GitlabError>().expect(
                format!(
                    "An unkown error happened while creating your new {}!",
                    resource
                )
                .as_str(),
            );

但我得到了同样的错误。

error[E0507]: cannot move out of a shared reference
   --> src/util.rs:12:33
    |
12  |             let json_response = response.clone().json::<gitlab::GitlabError>().expect(
    |                                 ^^^^^^^^^^^^^^^^^-----------------------------
    |                                 |                |
    |                                 |                value moved due to this method call
    |                                 move occurs because value has type `reqwest::blocking::Response`, which does not implement the `Copy` trait
    |

我还尝试以文本形式接收响应,然后用serde_json进行反序列化,但调用create_branch_response.json()也会导致移动。
如果你有兴趣阅读整个代码以获得更好的上下文,这里有一个包含这些(破碎的)更改的分支:https://github.com/Je12emy/shears-cli/tree/util_module。欢迎任何反馈

ws51t4hk

ws51t4hk1#

得到error[E0507]: cannot move out of a shared reference的原因是因为实际上克隆的是引用而不是实际的结构体(Response)。Rust在某些情况下会隐式地对函数调用的ref进行deref(参见函数和方法的隐式deref强制),但不适用于您的情况,因为reqwest::blocking::Response没有实现Clone。
See this example
为了解决借用问题,我建议您从request中获取bytes值,创建一个BufReader,然后使用serde_json::from_reader(reqwest内部使用这个)。然后你可以多次解析json。

相关问题