Cannot borrow `...` as mutable because it is also borrowed as immutable

Fair new to Rust, i'm having a problem that I just can't understand how to fix..

I have the following code:

let mut Response = Http::Response::new(stream);
let true_response = func(Request, &Response);
Response.write_response(&true_response);

That throws the following error (trimmed for easier reabability):

error[E0502]: cannot borrow `Response` as mutable because it is also borrowed as immutable
    let mut true_response = func(Request, &Response);
                                                                 --------- immutable borrow occurs here
   Response.write_response(&true_response);
   ^^^^^^^^^----------------------^^^^^^^^^^^^^^^^
   |                |
   |                |        immutable borrow later used by call
   | mutable borrow occurs here

Can anyone tell what I may be doing wrong?

true_response holds a reference to Response, which means that as long as true_response exists, you cannot do a mutable borrow of Response, which is required by write_response. The issue is basically the same as in the following, hopefully simpler example

    let mut mutable_string = String::from("hello");
    let immutable_borrow = &mutable_string;
    mutable_string.push_str(immutable_borrow); // error, can't change mutable_string while it's borrowed

The proper fix is a little hard to suggest without more context about what you're trying to do.

Building a HTTP server, so i'm creating a 'request' object to pass to the 'userss request handler, in which they'll return their response, and i'll use this to write to the client.

So Http::Response::new() is:

pub fn new (stream: TcpStream) -> Response {
    let Response = Response { stream };
    Response
}

func is:

fn(Http::Request::Request, &Http::Response::Response) -> &Http::Response::Response>

(So true_response is &Http::Response::Response)

And write_response is:

impl Response {
    pub fn write_response (&mut self, true_response: &Response) {
        //let contents = fs::read_to_string("index.html").unwrap();
        let contents = String::from("hello");

        let response = format!(
            "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}",
            contents.len(),
            contents
        );

        self.stream.write_all(response.as_bytes()).unwrap();
        self.stream.flush().unwrap();
    }
}

Yep, that’s the problem. The signature’s elided lifetimes expand to

fn func<'a>(request: Request, response: &'a Response) -> &'a Response

// or more technically correct if it’s a function pointer:
func: for <'a> fn(Request, &'a Response) -> &'a Response

Which means that true_response still needs the borrow from the Response variable in your original code to stay alive while it’s used. (This is getting confusing to talk about, you should consider following the Rust convention of using lowercase / snake_case variable names!)

On the other hand, a signature like your

fn write_response (self: &mut Response, true_response: &Response)

does (by being a &mut reference) state a guarantee that the self reference is to a Response that’s not "overlapping" (e.g. the same as) the target of the true_response reference.


I guess you might also want to tell us a bit about what a func with this signature can even do to the &Response parameter it gets other than just inspect and return it, and whether self and true_response are supposed to be the same or different references. (In particular, the code you showed above does not even use true_response yet.)

Ok thanks for the info! Yes, the true_response is unsed at the moment, but once I can get past these build errors, the true_response will hold the 'response body', which write_response will use, so for example of how i intend on using it:

// 50/50 pseudo-code
pub fn write_response (&self, true_response: Http::Response::Response) {
  let contents = true_response.body ;
  let response = format!(
    ...,
    contents
  };
  self.stream.write_all(contents);
}

I have been torn with the Rust conventions, as i've seen some 'mods' (not sure what best to call them, but I mean the std in std::collections or collections in std::collections), have a capitalised first letter, whilst the rust conventions warn me about this

My current thinking is i need to do something else with true_response, then destroy it to open up access to the Response variable (fix the error), but i'm guessing I have to rethink how this code is written.

I’m curious where you would’ve seen this. Yes, you can call them "mod(s)" or to use the non-abbreviated term: "modules", and those are also conventionally in snake_case, just like functions and methods. However in a path like this::is::a::path, it is possible that you see something capitalized like for example std::rc::Rc::downgrade(..). Perhaps this is what you’re referring to.

This is due to the fact that functions can not only be located in a module but also be namespaced under (i.e. associated with) a type. In Rust, types are conventionally in CamelCase, and Rc is a type.

E.g. this produces no warning

mod some_module {
    pub struct MyType;
    impl MyType {
        pub fn some_function() {}
    }
}

fn main() {
    some_module::MyType::some_function();
}

but you end up seing a capital MyType in the path some_module::MyType::some_function.

Yeah that's exactly what I mean :slight_smile: Coming from PHP/TS, I see the Http and Response as 'namespaces' or 'classes', hence my usage of capitalising. I'll go with lowercase anyways as it is the convention, plus it'll remove 24 warnings from the cargo build :wink:

solved it by changing let true_response = func(...) to func(...), as func will modify Response anyways, so what i have now is:

let mut Response = Http::Response::new(stream);
func(Request, &mut Response); // Should change the body of the Response
Response.write_response();

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.