I'm trying to write a Tic Tac Toe game in Rust, but this function for changing a field doesn't work and I don't know what's wrong with it:
fn change_field(mut table: [char; 9], field: i32, player: char) -> bool {
if field > 0 && field < 10 {
if table[field - 1] == ' ' {
table[field - 1] = player;
return true;
} else {
println!("That field isn't empty!");
}
} else {
println!("That field doesn't exist!");
}
return false;
}
I'm getting these errors:
src/main.rs:16:12: 16:26 error: the trait bound `[char]: std::ops::Index<i32>` is not satisfied [E0277]
src/main.rs:16 if table[field-1] == ' ' {
^~~~~~~~~~~~~~
src/main.rs:16:12: 16:26 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:16:12: 16:26 note: slice indices are of type `usize`
src/main.rs:17:13: 17:27 error: the trait bound `[char]: std::ops::Index<i32>` is not satisfied [E0277]
src/main.rs:17 table[field-1] = player;
^~~~~~~~~~~~~~
src/main.rs:17:13: 17:27 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:17:13: 17:27 note: slice indices are of type `usize`
src/main.rs:17:13: 17:27 error: the trait bound `[char]: std::ops::IndexMut<i32>` is not satisfied [E0277]
src/main.rs:17 table[field-1] = player;
^~~~~~~~~~~~~~
In later versions of Rust, I get these errors:
error[E0277]: the trait bound `i32: std::slice::SliceIndex<[char]>` is not satisfied
--> src/main.rs:3:12
|
3 | if table[field - 1] == ' ' {
| ^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[char]>` is not implemented for `i32`
= note: required because of the requirements on the impl of `std::ops::Index<i32>` for `[char]`
error[E0277]: the trait bound `i32: std::slice::SliceIndex<[char]>` is not satisfied
--> src/main.rs:4:13
|
4 | table[field - 1] = player;
| ^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[char]>` is not implemented for `i32`
= note: required because of the requirements on the impl of `std::ops::Index<i32>` for `[char]`
This is my first project in Rust so I don't have much experience with it. I tried to change the field to u32 too.
The reason is given to you in the notes:
note: slice indices are of type `usize`
slice indices are of type `usize` or ranges of `usize`
You need to cast the i32 value to usize, for example:
table[(field - 1) as usize]
Alternatively, consider using usize as the type of the field variable, if it makes sense in your application.
Related
I was trying to use Chain in Rust and encountered a problem that seems strange to me. I tried two code snippets that one of them works and the other doesn't. I tried to figure out the problem from the error message emitted by the compiler but couldn't find anything useful.
Snippet 1
fn main() {
let v: Vec<_> = (1..5).collect();
let u = v.iter().chain([6, 7, 8, 9, 10].iter().map(|i| i ));
u.for_each(|i| println!("{i}"));
}
Snippet 2
fn main() {
let v: Vec<_> = (1..5).collect();
let u = v.iter().chain([6, 7, 8, 9, 10].iter().map(|i| i+1 ));
u.for_each(|i| println!("{i}"));
}
The first snippet runs successfully but the second fails. The error message is:
Compiling playground v0.0.1 (/playground)
error[E0271]: type mismatch resolving `<[closure#src/main.rs:5:56: 5:63] as FnOnce<(&{integer},)>>::Output == &{integer}`
--> src/main.rs:5:28
|
5 | let u = v.iter().chain([6, 7, 8, 9, 10].iter().map(|i| i+1 ));
| ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&{integer}`, found integer
| |
| required by a bound introduced by this call
|
= note: required because of the requirements on the impl of `Iterator` for `Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>`
note: required by a bound in `std::iter::Iterator::chain`
error[E0599]: the method `for_each` exists for struct `std::iter::Chain<std::slice::Iter<'_, {integer}>, Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>>`, but its trait bounds were not satisfied
--> src/main.rs:6:7
|
6 | u.for_each(|i| println!("{i}"));
| ^^^^^^^^ method cannot be called on `std::iter::Chain<std::slice::Iter<'_, {integer}>, Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`<Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]> as Iterator>::Item = &{integer}`
which is required by `std::iter::Chain<std::slice::Iter<'_, {integer}>, Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>>: Iterator`
`std::iter::Chain<std::slice::Iter<'_, {integer}>, Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>>: Iterator`
which is required by `&mut std::iter::Chain<std::slice::Iter<'_, {integer}>, Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>>: Iterator`
Some errors have detailed explanations: E0271, E0599.
For more information about an error, try `rustc --explain E0271`.
error: could not compile `playground` due to 2 previous errors
I'm new to Rust and not familiar with many details. Can someone explain to me what's the problem here? Why changing the i to i+1 can cause a compile-time error?
This succeeds in the first case because both iterators are producing &i32 items. However, in the second case the first iterator is producing &i32 items, while the second iterator is producing i32 items -- the addition operation auto-derefs i and produces an integer. To chain two iterators, the item types must match exactly.
To clarify, the closures given to map in both snippets differ in their signature, which may be surprising since they look nearly identical!
|i| i accepts an &i32 and returns that &i32. In snippet 1, this is equivalent to |i: &i32| -> &i32 { i }.
|i| i + 1 accepts an &i32 and returns an i32, which is not the same type. In snippet 2, this is equivalent to |i: &i32| -> i32 { *i + 1 }.
To fix this, use the copied utility to convert the first iterator from &i32 items to i32 items by copy, which will match the type of the second iterator, allowing chaining:
fn main() {
let v: Vec<_> = (1..5).collect();
let u = v.iter().copied().chain([6, 7, 8, 9, 10].iter().map(|i| i+1 ));
u.for_each(|i| println!("{i}"));
}
Alternatively, convert the Vec to an interator with into_iter, which will consume the Vec and produce its values directly (not as references).
fn main() {
let v: Vec<_> = (1..5).collect();
let u = v.into_iter().chain([6, 7, 8, 9, 10].iter().map(|i| i+1 ));
u.for_each(|i| println!("{i}"));
}
Type inference can be handy, but it can also hide information from you. When you run into "type mismatch" errors like this and you can't figure them out, a good way to diagnose the problem is to start adding type annotations based on what you think the types actually are. Either an added type annotation will fix the problem by forcing a type that was incorrectly inferred, or Rust will complain that the type annotation doesn't match an actual type, which will expose your incorrect assumption and from there you should be able to solve the problem.
In this particular case, adding the return type annotation -> &i32 to the second closure would have led to a much more understandable error:
error[E0308]: mismatched types
--> src/main.rs:6:28
|
6 | .map(|i| -> &i32 { i+1 } )
| ^^^
| |
| expected `&i32`, found integer
| help: consider borrowing here: `&(i+1)`
The compiler's suggestion is incorrect, but this makes the situation much clearer and helps you see that your closure was returning i32 when you thought from your first snippet that it would return &i32.
In the below program why does the compiler error mention partially moved and not just moved? How is partial move happening here from x to z? If &mut T doesn't implement Copy trait, it should be moved and not partial move?
fn main() {
let mut y = 2;
let x = Some(&mut y);
match x {
None => (),
Some(z) => {
*z = 3;
println!("{}", z)},
};
println!("{:?}",x);
}
Below is the error from the playground
Compiling playground v0.0.1 (/playground)
error[E0382]: borrow of partially moved value: `x`
--> src/main.rs:10:21
|
6 | Some(z) => {
| - value partially moved here
...
10 | println!("{:?}",x);
| ^ value borrowed here after partial move
|
= note: partial move occurs because value has type `&mut i32`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving `x.0`
|
6 | Some(ref z) => {
| ^^^
For more information about this error, try `rustc --explain E0382`.
error: could not compile `playground` due to previous error
Consider the Option enum:
enum Option<T> {
Some(T),
None
}
Within that enum, Some(T) is actually a tuple struct, containing one field.
When you use pattern matching to extract the value of the inner T, that would be a partial move of one field of the single field tuple struct Some.
A partial move of a field from a struct that only has one field might not seem useful, but more generally there could be any number of fields in the struct.
See also:
Rust Reference section on Enumerations
I have this (most simplified) piece of code:
fn returns_closure() -> Box<dyn Fn(&u64)> {
let closure = |_| ();
Box::new(closure)
}
This does not compile with a rather unhelpful error message:
error[E0308]: mismatched types
--> src/main.rs:3:5
|
3 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `FnOnce<(&u64,)>`
found type `FnOnce<(&u64,)>`
However, when I don't bind the closure to a variable first, and create it directly in the constructor of the Box, it does compile:
fn returns_closure() -> Box<dyn Fn(&u64)> {
Box::new(|_| ())
}
Why does the first one fail to compile, and what is the difference between the two?
Edit:
Emouns answer seems to be correct.
I compiled the exact same code with the nightly toolchain (1.52.0), and got a better error:
error: implementation of `FnOnce` is not general enough
--> src/main.rs:3:5
|
3 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 u64)` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2`
As #frankenapps pointed out, if you use let closure = |_: &u64|(); then you don't get this error. So what is going on?
To try to figure this out I made the following edits that use explicit lifetimes (instead of having the compiler elide them for us) in an effort to get the same error message:
fn returns_closure<'a>() -> Box<dyn Fn(&'_ u64)> {
let closure = |_: &'a u64| ();
Box::new(closure)
}
Running this code gives us the following error message:
rror[E0308]: mismatched types
--> src/lib.rs:4:5
|
4 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `for<'r> Fn<(&'r u64,)>`
found type `Fn<(&'a u64,)>`
note: this closure does not fulfill the lifetime requirements
--> src/lib.rs:3:19
|
3 | let closure = |_: &'a u64| ();
| ^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> src/lib.rs:4:5
|
4 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `FnOnce<(&u64,)>`
found type `FnOnce<(&'a u64,)>`
note: this closure does not fulfill the lifetime requirements
--> src/lib.rs:3:19
|
3 | let closure = |_: &'a u64| ();
| ^^^^^^^^^^^^^^^
The error message is not the exact same, since we are using explicit lifetimes, but the type of error is still one type is more general than the other.
So what we see here might be an error in lifetime elision.
You can see that I have given the closure the same lifetime as the function ('a), however the function returns dyn Fn(&'_ u64). Here notice the '_ which is a stand-in for any lifetime, not just 'a.
Therefore, the return type &'_ u64is more general (accepts more lifetimes) than the closure (&'a u64) and we get the error.
I tried other lifetime combinations, but this one was the only one to give this type of error. But whether this is actually what is going on I cannot say.
With nightly rust:
Playground
struct Foo<T, F: Fn(&T, &T) -> T> {
value: T,
func: F
}
fn main() {
let lambda = |&x, &y| x + y;
let foo = Foo {
value: 5 as i32,
func: lambda
};
}
Error message:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/main.rs:8:15
|
8 | let foo = Foo {
| ^^^ one type is more general than the other
|
= note: expected type `std::ops::FnOnce<(&i32, &i32)>`
found type `std::ops::FnOnce<(&i32, &i32)>`
Note that the expected type and found type are character for character identical. Why is the error message saying that one type is more general than the other, while also saying that they are the same type?
With nightly rust:
This appears to be just a "bad" error message in a nightly build. In Rust 1.32 (stable), the errors tell you that this is a lifetime mismatch:
error[E0631]: type mismatch in closure arguments
--> src/main.rs:8:15
|
7 | let lambda = |&x, &y| x + y;
| -------------- found signature of `fn(&_, &_) -> _`
8 | let foo = Foo {
| ^^^ expected signature of `for<'r, 's> fn(&'r i32, &'s i32) -> _`
|
note: required by `Foo`
--> src/main.rs:1:1
|
1 | struct Foo<T, F: Fn(&T, &T) -> T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `for<'r, 's> <[closure#src/main.rs:7:18: 7:32] as std::ops::FnOnce<(&'r i32, &'s i32)>>::Output == i32`
--> src/main.rs:8:15
|
8 | let foo = Foo {
| ^^^ expected bound lifetime parameter, found concrete lifetime
|
note: required by `Foo`
--> src/main.rs:1:1
|
1 | struct Foo<T, F: Fn(&T, &T) -> T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Why is the error message saying that one type is more general than the other, while also saying that they are the same type?
The types differ only in lifetimes. The nightly message doesn't include lifetimes — perhaps in an attempt to reduce noise in cases where the lifetimes are not relevant. Obviously this is not at all helpful when lifetimes are the only difference between the types.
Consider reporting a bug to the Rust team.
I am trying to slice a vector and print it simultaneously in Rust. This is my code:
fn main() {
let a = vec![1, 2, 3, 4];
println!("{:?}", a[1..2]);
}
Error:
error[E0277]: the trait bound `[{integer}]: std::marker::Sized` is not satisfied
--> src/main.rs:6:5
|
6 | println!("{:?}", a[1..3]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `[{integer}]: std::marker::Sized` not satisfied
|
= note: `[{integer}]` does not have a constant size known at compile-time
= note: required by `std::fmt::ArgumentV1::new`
= note: this error originates in a macro outside of the current crate
How do I print this sliced vector?
You need to use a reference; it worked for me in Rust 1.13.
println!("{:?}", &a[1..3]);