The code case is from rustlings 'quiz2.rs'. I known command in ‘for(string,command)’ is borrowed from vector iterator. The command is borrowed, but why the 'n' Append(n) is also borrowed?
pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
// TODO: Complete the output declaration!
let mut output: Vec<String> = vec![];
for (string, command) in input.iter() {
// TODO: Complete the function body. You can do it!
match command {
Command::Uppercase => output.push(string.to_uppercase()),
Command::Trim => output.push(string.trim().to_string()),
Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(*n);
output.push(can_mv_str);
}
}
}
output
}
First, Vec::iter() returns an iterator over references to the elements of the vector, that is, &(String, Command).
Then, whenever you write a pattern for some specific structure, like the 2-element tuple (string, command) in the for loop, but the input is a reference to that structure, Rust matches "through" the reference and automatically gives you references to the elements (because it's not possible in general to not get references, since not every type is Copy).
So, the type of command is &Command. Then the same thing happens to the match command { and every variable binding in the match's pattern (that is, n) will be a reference too.
If you want to avoid this, what you have to do is explicitly write out matching against the references:
match command {
...
&Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(n);
output.push(can_mv_str);
}
}
Or, you can dereference the input to the match (this won't necessarily try to move out of the reference — as long as you don't bind any non-Copy values):
match *command {
...
Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(n);
output.push(can_mv_str);
}
}
Finally, if you want to completely avoid the magic and write out a program that is doing the whole thing explicitly, you also need to adjust the for pattern:
for &(ref string, ref command) in input.iter() {
The ref means "please don't try to move this value out of what I'm matching; just give me a reference to it. It's rarely seen in modern Rust because the automatic matching behavior I'm talking about makes it mostly unnecessary. This feature of Rust is called “match ergonomics”, because it saves you from writing a lot of & and ref all the time. But, as you've seen, it can lead to surprising behavior, and the old explicit style also lets you avoid dealing with needless references to Copy types like integers.
If you'd like to try writing Rust without ever using match ergonomics, to understand “what's really going on”, you can enable a Clippy restriction lint to mark any places where the pattern doesn't actually fit the type of what it's matching:
#[warn(clippy::pattern_type_mismatch)]
and run cargo clippy to see the new warnings. You'll probably find that there's quite a lot of patterns that are implicitly working on references!
This is because of RFC 2005. Before that, there used to be special syntax of ref and ref mut when you wanted to take a reference to an inner field in match.
What happens here is that your command is an &Command. You match on it but the arms are all Command. So command gets de-referenced automatically. But then, in Command::Append you take ownership of the inner n. This cannot happen as your command was a reference. So rust gives you a reference to n.
You can fix this in multiple ways. The easiest is to dereference the n yourself, like so:
match command {
Command::Append(&n) => ..., // n is owned here
...
}
This works when n is Copy. You can also do a let n = n.clone() in the match body itself if n is not Copy but is Clone.
You can also take ownership of command, like so:
match *command { // if Command is Copy
Command::Append(n) => ..., // n is owned here
...
}
// OR
match command.clone() { // if Command is Clone
Command::Append(n) => ..., // n is owned here
...
}
If you cannot do any of the above, then you will need to work with the reference itself or maybe change your iterator from input.iter() to input.into_iter() to get an owned Command from the start.
Related
I'm new to the Rust language and as I usually do when trying to pick up a language, I like to go through Euler Project questions. I want to get familiar with cargo and everything it offers, so I've created a cargo project called euler-project.
On startup, I want the program to ask the user which solution to run and have it run a function in the code that corresponds to the solution requested by the user.
I like to avoid huge chains of if / else if / else blocks, so I thought the match function would work well. Here's what I have.
use std::io;
fn main() {
// Solution selection. Every solution will be selectable here
let mut selection = String::new();
// Enum to hold every solved problem number for match control flow
enum Solutions {
P1, P2,
}
loop {
println!("Select the solution you would like to run. (Example: '32' would be Problem 32)");
io::stdin()
.read_line(&mut selection)
.expect("Input should be an integer.");
match selection {
Solutions::P1 => p1(),
Solutions::P2 => p2(),
}
}
}
fn p1() {
println!("p1")
}
fn p2() {
}
Currently this produces an error as follows:
...
21 | match selection {
| --------- this expression has type `std::string::String`
22 | Solutions::P1 => p1(),
| ^^^^^^^^^^^^^ expected struct `std::string::String`, found enum `main::Solutions`
What am I doing wrong here? If you know a better option for doing this type of control, please suggest it to me. I am also curious to know if there is anything similar to Python's interactive console mode that allows a user to run the code in the terminal, and to make function calls by simply typing function names and hitting enter.
You're comparing apples and oranges here. On the one hand, you have the string you have read from the user, and on the other hand you have values of type Solutions, but nowhere do you tell the compiler how to compare the two. The easiest way to do what you want is just to compare strings directly:
match selection.trim() {
"1" => p1(),
"2" => p2(),
_ => panic!("{} does not designate a valid problem!", selection),
}
Note the call to trim: the string returned by read_line includes the trailing newline, which you need to remove so that the comparisons will work.
Note also that you will need to call selection.clear() before read_line, otherwise the next iteration of the loop will append to the string instead of replacing it.
You can't match an enum with a String. You could try something like:
match selection.trim().parse::<i32>() {
Ok(x) if x == (Solutions::P1 as i32) => p1(),
Ok(x) if x == (Solutions::P2 as i32)=> p2(),
x => panic!{x},
}
I'm trying to learn Rust's lifetime rules by comparing it to similar concepts in C++, which I'm more familiar with. Most of the time, my intuition works really well and I can make sense the rule. However, in the following case, I'm not sure if my understanding is correct or not.
In Rust, a temporary value's lifetime is the end of its statement, except when the last temporary value is bound to a name using let.
struct A(u8);
struct B(u8);
impl A {
fn get_b(&mut self) -> Option<B> {
Some(B(self.0))
}
}
fn a(v: u8) -> A {
A(v)
}
// temporary A's lifetime is the end of the statement
// temporary B binds to a name so lives until the enclosing block
let b = a(1).get_b();
// temporary A's lifetime is the end of the statement
// temporary B's lifetime extends to the enclosing block,
// so that taking reference of temporary works similar as above
let b = &a(2).get_b();
If the temporary value is in an if condition, according to the reference, the lifetime is instead limited to the conditional expression.
// Both temporary A and temporary B drops before printing some
if a(3).get_b().unwrap().val <= 3 {
println!("some");
}
Now to the question:
If putting let in if condition, because of pattern matching, we are binding to the inner part of the temporary value. I'd expect the temporary value bound by let to be extended to the enclosing block, while other temporary values should still have a lifetime limited by the if condition.
(In this case actually everything is copied I would say even temporary B can be dropped, but that's a separate question.)
However, both temporaries' lifetimes are extended to the enclosing if block.
// Both temporary A and temporary B's lifetime are extended to the end of the enclosing block,
// which is the if statement
if let Some(B(v # 0...4)) = a(4).get_b() {
println!("some {}", v);
}
Should this be considered an inconsistency in Rust? Or am I misunderstanding and there is a consistent rule that can explain this behavior?
Full code example:
playground
The same thing implemented in C++ that matches my expectation
Note the output from Rust is
some 4
Drop B 4
Drop A 4
while the output from C++ is
Drop A 4
some 4
Drop B 4
I have read this Reddit thread and Rust issue, which I think is quite relevant, but I still can't find a clear set of lifetime rule that works for all the cases in Rust.
Update:
What I'm unclear about is why the temporary lifetime rule about if conditional expression does not apply to if let. I think the let Some(B(v # 0...4)) = a(4).get_b() should be the conditional expression, and thus the temporary A's lifetime should be limited by that, rather than the entire if statement.
The behaviour of extending temporary B's lifetime to the entire if statement is expected, because that is borrowed by the pattern matching.
An if let construct is just syntactic sugar for a match construct. let Some(B(v # 0...4)) = a(4).get_b() is not a conditional used in a regular if expression, because it is not an expression that evaluates to bool. Given your example:
if let Some(B(v # 0...4)) = a(4).get_b() {
println!("some {}", v);
}
It will behave exactly the same as the below example. No exceptions. if let is rewritten into match before the type or borrow checkers are even run.
match a(4).get_b() {
Some(B(v # 0...4)) => {
println!("some {}", v);
}
_ => {}
}
Temporaries live as long as they do in match blocks because they sometimes come in handy. Like if your last function was fn get_b(&mut self) -> Option<&B>, and if the temporary didn't live for the entire match block, then it wouldn't pass borrowck.
If conditionals don't follow the same rule because it's impossible for the last function call in an if conditional to hold a reference to anything. They have to evaluate to a plain bool.
See:
Rust issue 37612
I have data contained inside a Box, and would like to pattern match on it without accidentally copying the Box's contents from the heap to the stack; how do I do that?
Let's assume the following code:
enum SomeEnum {
SomeEntry,
AnotherEntry,
}
fn main() {
let boxed_value = Box::new(SomeEnum::AnotherEntry);
match *boxed_value {
SomeEnum::SomeEntry => {}
SomeEnum::AnotherEntry => {}
}
}
Does this copy the enum out of the box onto the stack and pattern match on that copy, or does it do the matching directly on the value pointed to by the box?
What about this variant?
use std::ops::Deref;
enum SomeEnum {
SomeEntry,
AnotherEntry,
}
fn main() {
let boxed_value = Box::new(SomeEnum::AnotherEntry);
match boxed_value.deref() {
SomeEnum::SomeEntry => {}
SomeEnum::AnotherEntry => {}
}
}
It seems that simply dereferencing a box does not automatically create a copy, otherwise one would not be able to create a reference to the contained value by using let x = &*boxed_value. This leads to a question about this syntax:
enum SomeEnum {
SomeEntry,
AnotherEntry,
}
fn main() {
let boxed_value = Box::new(SomeEnum::AnotherEntry);
match &*boxed_value {
SomeEnum::SomeEntry => {}
SomeEnum::AnotherEntry => {}
}
}
First: in Rust, there are no implicit costly copies, unlike in, for example, C++. Whereas in C++, the default action is "deep copy" (via copy constructor or similar), the default action in Rust is moving. A move is a shallow copy which (a) is usually very small and cheap and (b) can be removed by the optimizer in most cases. To get deep clones in Rust you have manually use .clone(). If you don't do that, you usually don't really have to worry about this.
Second: matching on an enum only looks at the discriminant of that enum (unless you bind enum fields, see below). That's the "tag" or the "metadata" which specifies which variant of the enum is stored in a value. That tag is tiny: it fits in 8 bits in almost all cases (enums with more than 256 variants are rare). So you don't need to worry about that. And in your case, we have a C-like enum without any fields. So the enum only stores the tag and hence is tiny, too.
So what about enum fields that might be costly to copy? Like this:
enum SomeEnum {
SomeEntry(String),
AnotherEntry,
}
let boxed_value = Box::new(SomeEnum::AnotherEntry);
match *boxed_value {
SomeEnum::SomeEntry(s) => drop::<String>(s), // make sure we own the string
SomeEnum::AnotherEntry => {},
}
So in this case one variant stores a String. Since deep-copying a string is somewhat costly, Rust won't do it implicitly. In the match arm we try to drop s and assert it's a String. That means we (meaning: the body of the match arm) own the string. So, if the match arm owns it but we didn't get the owned value from cloning it, that means that the outer function doesn't own it anymore. And in fact, if you try to use boxed_value after the match, you will get move errors from the compiler. So again, either you get a compiler error or no bad things automatically happen.
Furthermore, you can write SomeEnum::SomeEntry(ref s) in the match. In that case, the string is bound by reference to s (so the drop() call won't work anymore). In that case, we never move from boxed_value. This is something I call "deferred moving", but I'm not sure if that's an official term for it. But it just means: when pattern matching, the input value is not moved at all until a binding in the pattern moves from it.
Lastly, please take a look at this code and the generated assembly. The assembly is optimal. So once again: while you might be worried about accidental clones when you come from the C++ world, this is not really something you need to worry about in Rust.
A custom type by default is moved through default assignment. By implementing the Copy trait, I get "shallow copy semantics" through default assignment. I may also get "deep copy semantics" by implementing the Clone trait.
Is there a way to force a move on a Copy type?
I tried using the move keyword and a closure (let new_id = move || id;) but I get an error message. I'm not into closures yet, but, from seeing them here and there, I thought that that would have worked.
I don't really understand your question, but you certainly seem confused. So I'll address what seems to be the root of this confusion:
The C++ notions of copy/move I think I get correctly, but this 'everything is a memcpy anyway' is, well, it hasn't been very intuitive any time I read it
When thinking about Rust's move semantics, ignore C++. The C++ story is way more complicated than Rust's, which is remarkably simple. However, explaining Rust's semantics in terms of C++ is a mess.
TL;DR: Copies are moves. Moves are copies. Only the type checker knows the difference. So when you want to "force a move" for a Copy type, you are asking for something you already have.
So we have three semantics:
let a = b where b is not Copy
let a = b where b is Copy
let a = b.clone() where b is Clone
Note: There is no meaningful difference between assignment and initialization (like in C++) - assignment just first drops the old value.
Note: Function call arguments work just like assignment. f(b) assigns b to the argument of f.
First things first.
The a = b always performs a memcpy.
This is true in all three cases.
When you do let a = b, b is memcpy'd into a.
When you do let a = b.clone(), the result of b.clone() is memcpy'd into a.
Moves
Imagine b was a Vec. A Vec looks like this:
{ &mut data, length, capacity }
When you write let a = b you thus end up with:
b = { &mut data, length, capacity }
a = { &mut data, length, capacity }
This means that a and b both reference &mut data, which means we have aliased mutable data.
The type-system doesn't like this so says we can't use b again. Any access to b will fail at compile-time.
Note: a and b don't have to alias heap data to make using both a bad idea. For example, they could both be file handles - a copy would result in the file being closed twice.
Note: Moves do have extra semantics when destructors are involved, but the compiler won't let you write Copy on types with destructors anyway.
Copies
Imagine b was an Option<i32>. An Option<i32> looks like this:
{ is_valid, data }
When you write let a = b you thus end up with:
b = { is_valid, data }
a = { is_valid, data }
These are both usable simultaneously. To tell the type system that this is the case, one marks Option<i32> as Copy.
Note: Marking something copy doesn't change what the code does. It only allows more code. If you remove a Copy implementation, your code will either error or do exactly the same thing. In the same vein, marking a non-Copy type as Copy will not change any compiled code.
Clones
Imagine you want to copy a Vec, then. You implement Clone, which produces a new Vec, and do
let a = b.clone()
This performs two steps. We start with:
b = { &mut data, length, capacity }
Running b.clone() gives us an additional rvalue temporary
b = { &mut data, length, capacity }
{ &mut copy, length, capacity } // temporary
Running let a = b.clone() memcpys this into a:
b = { &mut data, length, capacity }
{ &mut copy, length, capacity } // temporary
a = { &mut copy, length, capacity }
Further access of the temporary is thus prevented by the type system, since Vec is not Copy.
But what about efficiency?
One thing I skipped over so far is that moves and copies can be elided. Rust guarantees certain trivial moves and copies to be elided.
Because the compiler (after lifetime checking) sees the same result in both cases, these are elided in exactly the same way.
Wrap the copyable type in another type that doesn't implement Copy.
struct Noncopyable<T>(T);
fn main() {
let v0 = Noncopyable(1);
let v1 = v0;
println!("{}", v0.0); // error: use of moved value: `v0.0`
}
New Answer
Sometimes I just want it to scream at me "put a new value in here!".
Then the answer is "no". When moving a type that implements Copy, both the source and destination will always be valid. When moving a type that does not implement Copy, the source will never be valid and the destination will always be valid. There is no syntax or trait that means "let me pick if this type that implements Copy acts as Copy at this time".
Original Answer
I just want to sometimes say "yeah, this type is Copy, but I really don't need this value in this variable anymore. This function takes an arg by val, just take it."
It sounds like you are trying to do the job of the optimizer by hand. Don't worry about that, the optimizer will do that for you. This has the benefit of not needing to worry about it.
Moves and copies are basically just the same runtime operation under the covers. The compiler inserts code to make a bitwise copy from the first variable's address into the second variable's address. In the case of a move, the compiler also invalidates the first variable so that if it subsequently used it will be a compile error.
Even so, I think there would be still be validity if Rust language allowed a program to say the assignment was an explicit move instead of a copy. It could catch bugs by preventing inadvertant references to the wrong instance. It might also generate more efficient code in some instances if the compiler knows you don't need two copies and could jiggle the bindings around to avoid the bitwise copy.
e.g. if you could state a = move assignment or similar.
let coord = (99.9, 73.45);
let mut coord2 = move coord;
coord2.0 += 100.0;
println!("coord2 = {:?}", coord2);
println!("coord = {:?}", coord); // Error
At runtime, copies and moves, in Rust, have the same effect. However, at compile-time, in the case of a move, the variable which an object is moved from is marked as unusable, but not in the case of a copy.
When you're using Copy types, you always want value semantics, and object semantics when not using Copy types.
Objects, in Rust, don't have a consistent address: the addresses often change between moves because of the runtime behavior, i.e. they are owned by exactly one binding. This is very different from other languages!
In Rust when you use (or move, in Rust's terms) a value that is Copy, the original value is still valid. If you want to simulate the case that like other non-copyable values, to invalidate after a specific use, you can do:
let v = 42i32;
// ...
let m = v;
// redefine v such that v is no longer a valid (initialized) variable afterwards
// Unfortunately you have to write a type here. () is the easiest,
// but can be used unintentionally.
let v: ();
// If the ! type was stabilized, you can write
let v: !;
// otherwise, you can define your own:
enum NeverType {};
let v: NeverType;
// ...
If you later change v to something that is not Copy, you don't have to change the code above to avoid using the moved value.
Correction on some misunderstanding on the question
The difference between Clone and Copy is NOT "shallow copy" and "deep copy" semantics. Copy is "memcpy" semantics and Clone is whatever the implementors like, that is the only difference. Although, by definition, things which require a "deep copy" are not able to implement Copy.
When a type implements both Copy and Clone, it is expected that both have the same semantics except that Clone can have side effects. For a type that implements Copy, its Clone should not have "deep copy" semantics and the cloned result is expected to be the same as a copied result.
As an attempt, if you want to use the closure to help, you probably wanted to run the closure, like let new_id = (move || id)();. If id is copy then id is still valid after the move, so this does not help, at all.
I downloaded the nightly build of Rust and attempted to build my code, but interestingly enough I realized mut_iter() no longer exists. What was the reason for removing the ability to create mutable iterators for strings? I have the function:
//invert hex picture, this is used in the print_bitmap function
// to save space and break apart one large code base.
pub fn invert_ascii_hex_string(line: &mut [std::ascii::Ascii]) {
for c in line.mut_iter() {
*c = match c.to_char() {
'x' => ' ',
_ => 'x'
}.to_ascii();
}
}
and now I'm not sure how to go about accomplishing this without a mutable iterator. What could I now use to still iterate through the list and change each value?
Try iter_mut() instead of mut_iter()