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
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
}
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!)
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:
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.
Yeah that's exactly what I mean 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