for a given set of iterators a, b, c, one can chain them successfully with a.chain(b).chain(c). Since the CLI util I am trying to write provides a vector of paths (strings, --dirs "a/b/c" "d/e/f" ...), I would like to use walkd_dir on each of them and then chain them together. My first thought is:
fn main() {
let a = 0..3;
let b = 3..6;
let c = 6..9;
let v = vec![b, c];
v.iter().cloned().fold(a, |acc, e| acc.chain(e));
}
http://is.gd/hfNQd2, returns
<anon>:6:40: 6:52 error: mismatched types:
expected `core::ops::Range<_>`,
found `core::iter::Chain<core::ops::Range<_>, core::ops::Range<_>>`
(expected struct `core::ops::Range`,
found struct `core::iter::Chain`) [E0308]
<anon>:6 v.iter().cloned().fold(a, |acc, e| acc.chain(e));
Another attempt http://is.gd/ZKdxZM, although a.chain(b).chain(c) works.
Use flat_map:
fn main() {
let a = 0..3;
let b = 3..6;
let c = 6..9;
let v = vec![a, b, c];
v.iter().flat_map(|it| it.clone());
}
As the error message states, the type of a Range is different than the type of Chain<Range, Range>, and the type of the accumulator in the call the fold must always be consistent. Otherwise, what would the return type be from the fold if there were no items in the vector?
The simplest solution is to use a trait object, specifically Box<Iterator>:
type MyIter = Box<Iterator<Item=i32>>;
fn main() {
let a = 0..3;
let b = 3..6;
let c = 6..9;
let v = vec![b, c];
let z = v.into_iter().fold(Box::new(a) as MyIter, |acc, e| {
Box::new(acc.chain(Box::new(e) as MyIter)) as MyIter
});
for i in z {
println!("{}", i);
}
}
This adds a level of indirection but unifies the two concrete types (Range, Chain) as a single type.
A potentially more efficient but longer-to-type version would be to create an enum that represented either a Range or a Chain, and then implement Iterator for that new type.
Actually, I don't think the enum would work as it would require a recursive definition, which is not allowed.
Related
in rust-lang, what's the difference between static_fly::<Number>(number); and static_fly(number);
here is a demo:
enum Number {
Zero,
One,
Two,
}
trait Fly {
fn fly(&self);
}
impl Fly for Number {
fn fly(&self) {
println!("flying number: {}", self)
}
}
// 静态分发
fn static_fly<T: Fly>(f: T){
print!("静态分发\t");
f.fly()
}
fn main() {
let number = Zero;
// 泛型的分发调用
static_fly(number); // <-- here is the 1st method for calling static_fly
// static_fly::<Number>(number); // <-- here is the 2nd method for calling static_fly
}
what's the difference between this two calling.
The two methods of calling the function are equivalent in this case.
Given enough information, Rust can infer generic type arguments. In the case of static_fly(number) the compiler has inferred that T is Number. In the case of static_fly::<Number>(number) you are just providing the type for the type argument T explicitly.
This is very similar to other kinds of inference the compiler performs. For example, both of these statements are also equivalent:
let number = Zero;
let number: Number = Zero;
It's the same principle -- in one case we specify the type, in the other we let the compiler figure it out.
Its the same thing as let a = b; compared to let a: Type = b;. It gives you the option to explicitly state which type is used in an operation. Normally Rust can infer what you want to do, however if there is any ambiguity the compiler will ask you to explicitly specify a type.
For example, the most common instance of this I run into is when calling .collect() on an iterator.
fn foo(vals: &[u32]) -> Vec<u32> {
// In this case there is no ambiguity since the result of collect must
// be a `Vec<u32>`. Since the compiler can infer the type, we don't need
// to state what type collect uses.
vals.iter()
.map(|x| x * 2)
.collect()
}
fn bar(vals: &[u32]) -> u32 {
// In this case the compiler is unable to infer a type as collect can
// create any type that can be initialized with an iterator.
let mut a = vals.iter()
.map(|x| x * 2)
.collect();
a.sort();
a[0]
}
For this example there are a couple ways you can fix bar.
// State the type of a so the compiler can infer collect's types
let mut a: Vec<u32> = vals.iter()
.map(|x| x * 2)
.collect();
// State the types used by the function in question but let the compiler infer a's type
let mut a = vals.iter()
.map(|x| x * 2)
.collect::<Vec<u32>>();
Another option is to only partially state the type in question. A type name can be replaced with an underscore to tell the compiler to infer that part of a type. This is generally my preferred way of handling this specific case.
// Tell the compiler we will collect items to a Vec, but let it infer the content type
let mut a = vals.iter()
.map(|x| x * 2)
.collect::<Vec<_>>();
What is the purpose of & in the code &i in list? If I remove the &, it produces an error in largest = i, since they have mismatched types (where i is &32 and i is i32). But how does &i convert i into i32?
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for &i in list {
if i > largest {
largest = i;
}
}
largest
}
fn main() {
let hey = vec![1, 3, 2, 6, 90, 67, 788, 12, 34, 54, 32];
println!("The largest number is: {}", largest(&hey));
}
Playground
It seems like it is somehow dereferencing, but then why in the below code, is it not working?
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
It says:
4 | hey = &&x;
| ^^^ expected i32, found &&i32
|
= note: expected type `i32`
found type `&&i32`
So normally when you use for i in list, the loop variable i would be of type &i32.
But when instead you use for &i in list, you are not dereferencing anything, but instead you are using pattern matching to explicitly destructure the reference and that will make i just be of type i32.
See the Rust docs about the for-loop loop variable being a pattern and the reference pattern that we are using here. See also the Rust By Example chapter on destructuring pointers.
An other way to solve this, would be to just keep i as it is and then comparing i to a reference to largest, and then dereferencing i before assigning to largest:
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for i in list {
if i > &largest {
largest = *i;
}
}
largest
}
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
This simply doesn't work, because here you are assigning hey, which is an i32, to a reference to a reference to an i32. This is quite unrelated to the pattern matching and destructuring in the loop variable case.
This is the effect of destructuring. I won't completely describe that feature here, but in short:
In many syntax contexts (let bindings, for loops, function arguments, ...) , Rust expects a "pattern". This pattern can be a simple variable name, but it can also contain some "destructuring elements", like &. Rust will then bind a value to this pattern. A simple example would be something like this:
let (a, b) = ('x', true);
On the right hand side there is a value of type (char, bool) (a tuple). This value is bound to the left hand pattern ((a, b)). As there is already a "structure" defined in the pattern (specifically, the tuple), that structure is removed and a und b bind to the tuple's elements. Thus, the type of a is char and the type of b is bool.
This works with a couple of structures, including arrays:
let [x] = [true];
Again, on the right side we have a value of type [bool; 1] (an array) and on the left side we have a pattern in the form of an array. The single array element is bound to x, meaning that the type of x is bool and not [bool; 1]!
And unsurprisingly, this also works for references!
let foo = 0u32;
let r = &foo;
let &c = &foo;
Here, foo has the type u32 and consequently, the expression &foo has the type &u32. The type of r is also &u32, as it is a simple let binding. The type of c is u32 however! That is because the "reference was destructured/removed" by the pattern.
A common misunderstanding is that syntax in patterns has exactly the opposite effect of what the same syntax would have in expressions! If you have a variable a of type [T; 1], then the expression [a] has the type [[T; 1]; 1] → it adds stuff. However, if you bind a to the pattern [c], then y has the type T → it removes stuff.
let a = [true]; // type of `a`: `[bool; 1]`
let b = [a]; // type of `b`: `[[bool; 1]; 1]`
let [c] = a; // type of `c`: `bool`
This also explains your question:
It seems like it is somehow dereferencing, but then why in the below code, it is not working?
fn main() {
let mut hey:i32 = 32;
let x:i32 = 2;
hey = &&x;
}
Because you use & on the expression side, where it adds a layer of references.
So finally about your loop: when iterating over a slice (as you do here), the iterator yields reference to the slice's elements. So in the case for i in list {}, i has the type &i32. But the assignment largest = i; requires a i32 on the right hand side. You can achieve this in two ways: either dereference i via the dereference operator * (i.e. largest = *i;) or destructure the reference in the loop pattern (i.e. for &i in list {}).
Related questions:
Iterating over a slice's values instead of references in Rust?
Why is & needed to destructure a list of tuples during iteration?
What is the purpose of & in the code &i in list? If I remove the &, it produces an error in largest = i, since they have mismatched types (where i is &32 and i is i32). But how does &i convert i into i32?
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for &i in list {
if i > largest {
largest = i;
}
}
largest
}
fn main() {
let hey = vec![1, 3, 2, 6, 90, 67, 788, 12, 34, 54, 32];
println!("The largest number is: {}", largest(&hey));
}
Playground
It seems like it is somehow dereferencing, but then why in the below code, is it not working?
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
It says:
4 | hey = &&x;
| ^^^ expected i32, found &&i32
|
= note: expected type `i32`
found type `&&i32`
So normally when you use for i in list, the loop variable i would be of type &i32.
But when instead you use for &i in list, you are not dereferencing anything, but instead you are using pattern matching to explicitly destructure the reference and that will make i just be of type i32.
See the Rust docs about the for-loop loop variable being a pattern and the reference pattern that we are using here. See also the Rust By Example chapter on destructuring pointers.
An other way to solve this, would be to just keep i as it is and then comparing i to a reference to largest, and then dereferencing i before assigning to largest:
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for i in list {
if i > &largest {
largest = *i;
}
}
largest
}
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
This simply doesn't work, because here you are assigning hey, which is an i32, to a reference to a reference to an i32. This is quite unrelated to the pattern matching and destructuring in the loop variable case.
This is the effect of destructuring. I won't completely describe that feature here, but in short:
In many syntax contexts (let bindings, for loops, function arguments, ...) , Rust expects a "pattern". This pattern can be a simple variable name, but it can also contain some "destructuring elements", like &. Rust will then bind a value to this pattern. A simple example would be something like this:
let (a, b) = ('x', true);
On the right hand side there is a value of type (char, bool) (a tuple). This value is bound to the left hand pattern ((a, b)). As there is already a "structure" defined in the pattern (specifically, the tuple), that structure is removed and a und b bind to the tuple's elements. Thus, the type of a is char and the type of b is bool.
This works with a couple of structures, including arrays:
let [x] = [true];
Again, on the right side we have a value of type [bool; 1] (an array) and on the left side we have a pattern in the form of an array. The single array element is bound to x, meaning that the type of x is bool and not [bool; 1]!
And unsurprisingly, this also works for references!
let foo = 0u32;
let r = &foo;
let &c = &foo;
Here, foo has the type u32 and consequently, the expression &foo has the type &u32. The type of r is also &u32, as it is a simple let binding. The type of c is u32 however! That is because the "reference was destructured/removed" by the pattern.
A common misunderstanding is that syntax in patterns has exactly the opposite effect of what the same syntax would have in expressions! If you have a variable a of type [T; 1], then the expression [a] has the type [[T; 1]; 1] → it adds stuff. However, if you bind a to the pattern [c], then y has the type T → it removes stuff.
let a = [true]; // type of `a`: `[bool; 1]`
let b = [a]; // type of `b`: `[[bool; 1]; 1]`
let [c] = a; // type of `c`: `bool`
This also explains your question:
It seems like it is somehow dereferencing, but then why in the below code, it is not working?
fn main() {
let mut hey:i32 = 32;
let x:i32 = 2;
hey = &&x;
}
Because you use & on the expression side, where it adds a layer of references.
So finally about your loop: when iterating over a slice (as you do here), the iterator yields reference to the slice's elements. So in the case for i in list {}, i has the type &i32. But the assignment largest = i; requires a i32 on the right hand side. You can achieve this in two ways: either dereference i via the dereference operator * (i.e. largest = *i;) or destructure the reference in the loop pattern (i.e. for &i in list {}).
Related questions:
Iterating over a slice's values instead of references in Rust?
Why is & needed to destructure a list of tuples during iteration?
I'm trying to retrieve a key from a BTreeMap and manipulate it in subsequent code.
use std::collections::BTreeMap;
fn main() {
let mut map: BTreeMap<u64, u64> = BTreeMap::new();
map.entry(0).or_insert(0);
// It seems like this should work:
let y = map[0] + 1; // expected reference, found integral variable
// Other things I've tried:
let value_at_0 = map[0]; // expected reference, found integral variable
let ref value_at_0 = map[0]; // expected reference, found integral variable
let y = value_at_0 + 1;
let y = (&map[0]) + 1; // expected reference, found integral variable
let y = (&mut map[0]) + 1; // binary operation `+` cannot be applied to type `&mut u64`
let y = (*map[0]) + 1; // type `u64` cannot be dereferenced
println!("{}", y);
}
The error is particularly confusing, since I would think an integral variable would be precisely the kind of thing you could add 1 to.
To show what I would like this code to do, here is how this would be implemented in Python:
>>> map = {}
>>> map.setdefault(0, 0)
0
>>> y = map[0] + 1
>>> print(y)
1
For SEO purposes, since my Googling failed, the originating error in somewhat more complex code is expected reference, found u64
For reference, the full compilation error is:
error[E0308]: mismatched types
--> ./map_weirdness.rs:8:15
|
8 | let y = map[0] + 1; // expected reference, found integral variable
| ^^^^^^ expected reference, found integral variable
|
= note: expected type `&u64`
= note: found type `{integer}`
The bug was in what was being passed to [], though the error highlighted the whole map[0], suggesting that the error was in the type of the value of map[0] when it was actually in computing the value. The correct implementation needs to pass a reference to [] as follows:
use std::collections::BTreeMap;
fn main() {
let mut map: BTreeMap<u64, u64> = BTreeMap::new();
map.entry(0).or_insert(0);
let y = map[&0] + 1;
println!("{}", y);
}
This code fails as expected at let c = a; with compile error "use of moved value: a":
fn main() {
let a: &mut i32 = &mut 0;
let b = a;
let c = a;
}
a is moved into b and is no longer available for an assignment to c. So far, so good.
However, if I just annotate b's type and leave everything else alone:
fn main() {
let a: &mut i32 = &mut 0;
let b: &mut i32 = a;
let c = a;
}
the code fails again at let c = a;
But this time with a very different error message: "cannot move out of a because it is borrowed ... borrow of *a occurs here: let b: &mut i32 = a;"
So, if I just annotate b's type: no move of a into b, but instead a "re"-borrow of *a?
What am I missing?
Cheers.
So, if I just annotate b's type: no move of a into b, but instead a "re"-borrow of *a?
What am I missing?
Absolutely nothing, as in this case these two operations are semantically very similar (and equivalent if a and b belong to the same scope).
Either you move the reference a into b, making a a moved value, and no longer available.
Either you reborrow *a in b, making a unusable as long as b is in scope.
The second case is less definitive than the first, you can show this by putting the line defining b into a sub-scope.
This example won't compile because a is moved:
fn main() {
let a: &mut i32 = &mut 0;
{ let b = a; }
let c = a;
}
But this one will, because once b goes out of scope a is unlocked:
fn main() {
let a: &mut i32 = &mut 0;
{ let b = &mut *a; }
let c = a;
}
Now, to the question "Why does annotating the type of b change the behavior ?", my guess would be:
When there is no type annotation, the operation is a simple and straightforward move. Nothing is needed to be checked.
When there is a type annotation, a conversion may be needed (casting a &mut _ into a &_, or transforming a simple reference into a reference to a trait object). So the compiler opts for a re-borrow of the value, rather than a move.
For example, this code is perflectly valid:
fn main() {
let a: &mut i32 = &mut 0;
let b: &i32 = a;
}
and here moving a into b would not make any sense, as they are of different type. Still this code compiles: b simply re-borrows *a, and the value won't be mutably available through a as long as b is in scope.
To complement #Levans's answer on the specific question "Why does annotating the type change the behaviour?":
When you don't write the type, the compiler performs a simple move. When you do put the type, the let statement becomes a coercion site as documented in "Coercion sites":
Possible coercion sites are:
let statements where an explicit type is given.
In the present case the compiler performs a reborrow coercion, which is a special case of coercion going from &mut to &mut, as explained in this issue comment on GitHub.
Note that reborrowing in general and reborrow coercion in particular are currently poorly documented. There is an open issue on the Rust Reference to improve that point.