here again a problem w.r.t. E0502. Alas, I cannot find an explanation myself by reading
the earlier postings.
Just for learning Rust, I'm trying this:
fn my_splitter( _aStr: &str ) -> Vec< &str > {
/* This code is working well, returning a new _nVec: Vec< &str > */
}
fn main() {
let mut _args: Vec<String> = std::env::args().collect();
_args[ 0 ] = "try other value".to_string(); /* Simple println!() dropped, before and after */
for s in my_splitter( &_args[ 0 ] ).iter() {
println!( "//TT: s='{}'", s ); //ok, if code is running without the next line
_args.push( s.to_string() ); //error[E0502] - details see below
}
println!( "//T: _args='{:?}'", _args );
}
Alas, getting error[E0502], which seems strange since it looks as if the immutable borrow
has already ended before the mutable borrow is tried:
error[E0502]: cannot borrow `_args` as mutable because it is also borrowed as immutable
--> src/main.rs:25:9
|
23 | for s in my_splitter( &_args[ 0 ] ).iter() {
| ----- - immutable borrow ends here
| |
| immutable borrow occurs here
24 | println!( "//TT: s='{}'", s );
25 | _args.push( s.to_string() );
| ^^^^^ mutable borrow occurs here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0502`.
And rustc --explain E0502 didn't help me out.
Can anybody help me understanding this? - And/Or proposing a working solution?
Thanks.
guevol
PS: My background includes C/C++, Java, JavaScript; but I'm a Rust newbie - obviously
First off, please put your code in a code block by bracketing with "```". It makes it much easier to read.
I'm also new to rust so I might be wrong, but it looks like _args is borrowed as immutable because of your call to my_splitter( &_args[0]).iter().
my_splitter gets an immutable reference to _args[0] that lives until the iterator goes out of scope. It would be helpful to see the source of your my_splitter() function. That way I could test your code, but maybe it does something like this?
I got your code running by passing a cloned value to my_splitter instead of a reference to the value owned by _args. playground here
fn main() {
//let mut _args: Vec = std::env::args().collect();
let mut _args: Vec<String> = Vec::new();
_args.push( "try other value".to_string() );
for s in my_splitter(&_args[0].clone()).iter() {
println!("//TT: s='{}'", s);
_args.push(s.to_string());
}
println!("//T: _args='{:?}'", _args);
}
Side note, the underscore variable syntax is used to indicate that a variable will never be used. You're obviously going to use this variable, so just args would be a better name.
Repetition of my first reply, which is not displayed for unknow reason...
Thanks for your quick reply and sorry for the bad format - I had tried HTML-tt-blocks.
With the essential code of my_splitter() and all formatted within triple-backticks:
fn my_splitter( aStr: &str ) -> Vec< &str > { /* Without its println!() lines */
let nVec: Vec< &str > = aStr.split( ' ' ).collect();
nVec
}
fn main() { /* Without some of its println!() */
let mut my_args: Vec<String> = std::env::args().collect();
my_args[ 0 ] = "try other value".to_string();
for s in my_splitter( &my_args[ 0 ] ).iter() {
println!( "//TT: s='{}'", s ); //ok, if code is running without the next line
my_args.push( s.to_string() ); //error[E0502] - details see below
}
println!( "//T: my_args='{:?}'", my_args );
}
And still the same error due to the merely non-essential changes:
error[E0502]: cannot borrow `my_args` as mutable because it is also borrowed as immutable
--> src/main.rs:18:9
|
16 | for s in my_splitter( &my_args[ 0 ] ).iter() {
| ------- - immutable borrow ends here
| |
| immutable borrow occurs here
17 | println!( "//TT: s='{}'", s );
18 | my_args.push( s.to_string() );
| ^^^^^^^ mutable borrow occurs here
Please, be aware that .iter() concerns the returned Vec object, which, in order to block
the original my_args, must contain references to original entries of my_args. BUT why
then is the compiler claiming "immutable borrow ends here" at that very spot?
OK, I think, the crux is what I just said about the references to original entries.
Do you agree?
Is there a reason that this .clone() is not sufficient to solve your problem?
I'm also unable to recreate your error. I get the following error from your original code, which makes the clone solution seem pretty straight forward.
error[E0502]: cannot borrow `_args` as mutable because it is also borrowed as immutable
--> src/main.rs:9:9
|
7 | for s in my_splitter(&_args[0]).iter() {
| -----------------------------
| | |
| | immutable borrow occurs here
| immutable borrow later used here
8 | println!("//TT: s='{}'", s);
9 | _args.push(s.to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
a) OK, your proposal of calling my_splitter() with a clone is working well;
while within my_splitter() I can stick to the "old" variant let nVec: Vec< &str > = aStr.split( ' ' ).collect();
Alas, that puts some burden on the user of my_splitter().
b) Hence, why is my forgoing try with let nVec: Vec< &str > = aStr.split( ' ' ).clone().collect();
NOT working?
Any idea where a reference to the original comes into play in this case b?
Ahh, I understand your concern now. How about instead of taking in a borrowed value and returns a vector of &str, my_splitter takes in a borrowed value and returns a vector of owned String?
Now you should be able to get rid of the .clone() in main().
EDIT: To be honest, I'm not exactly sure why something like your case b or aStr.split_whitespace().map(|x| x.clone()).collect() still raises the same error in main(). Perhaps someone else will come along and enlighten us both!
W.r.t. your "EDIT": The only [abstract] reason for this behaviour I can think of is:
the references themselves get cloned, not the object they are referring to...