I am just starting to learn Rust. The entry method an Entry enum, which can be accessed via the match function. But then I don't get why it doesn't compile and it panics.
Can someone explain please what I'm understanding wrong?
let mut scores: HashMap<String, u32> = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
let a = 10;
match scores.entry("poneyland".to_string()) {
Occupied(o) => o.remove_entry(),
Vacant(o) => o.insert(37),
}
But then I don't get why it doesn't compile and it panics.
It can't both fail to compile and panic, since panic is a runtime behaviour. Either way, when there is an error it is usually a good idea to post it, as that makes diagnostic much easier, especially in Rust which generally has pretty helpful error messages.
In this case, the compilation error tells you exactly what's what:
error[E0308]: `match` arms have incompatible types
--> src/main.rs:15:22
|
13 | / match scores.entry("poneyland".to_string()) {
14 | | Occupied(o) => o.remove_entry(),
| | ---------------- this is found to be of type `(String, u32)`
15 | | Vacant(o) => o.insert(37),
| | ^^^^^^^^^^^^ expected tuple, found `&mut u32`
16 | | }
| |_____- `match` arms have incompatible types
|
= note: expected tuple `(String, u32)`
found mutable reference `&mut u32`
You pretty much just need to read the message, and possibly the expanded document.
What it boils down to is a rust match is an expression, meaning it has a value of a specific type, meaning all arms must have values of the same type (or a compatible type e.g. !).
Here, as the compiler error tells you, in one arm you're calling remove_entry which returns a tuple of (key, value), while in the other arm you're calling insert which returns a mutable reference to the inserted value.
These types are obviously not compatible.
The easiest way to fix this is to make them compatible by... suppressing the results entirely since you're not using them: convert the arm expressions to arm blocks and terminate the expressions with ;. That makes the expressions into statements and suppresses their value, implicitly returning () instead:
match scores.entry("poneyland".to_string()) {
Occupied(o) => {
o.remove_entry();
}
Vacant(o) => {
o.insert(37);
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1b885daa2a4eaa6d9d7c366753f6c2aa
Related
I have this rust method error message:
error[E0277]: the `?` operator can only be used on `Option`s,
not `Result`s, in an async function that returns `Option`
I must admit, I often encounter Rust error messages which appear confusing to me, while to most other coders they make absolute sense.
So, I apologize in advance for posting this question.
First of all: what does that second comma in the error message mean? Should I read it as the following:
"If an async function call [within another function] returns an enum of the type Result then the ? operator can only be applied if, and only if, the respective [other] function also returns an enum of type Result and not an enum of type Option"
Pardon my verbose language. I hope I got my point across.
What also got me confused was the error message with that very same Reference i.e. error[E0277] , which is listed in the official rust error codes index, states:
"You tried to use a type which doesn't implement some trait in a place which expected that trait."
In which universe do these two error messages have anything in common, except for the identical reference number?
And here's the entire error block, which Rust produced:
error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in an async function that returns `Option`
--> src/utils/tokenizer.rs:72:73
|
70 | pub async fn clear(&self) -> Option<String> {
| _________________________________________________-
71 | | let mut conn = self.pool.get().await.unwrap();
72 | | let mut iter: redis::AsyncIter<i32> = conn.sscan("my_set").await?;
| | ^ use `.ok()?` if you want to discard the `Result<Infallible, Red
Error>` error information
73 | | while let Some(element) = iter.next_item().await {
... |
79 | | Some(String::from("A"))
80 | | }
| |_____- this function returns an `Option`
|
= help: the trait `FromResidual<Result<Infallible, RedisError>>` is not implemented for `std::option::Option<std::string::String>`
= help: the following other types implement trait `FromResidual<R>`:
<std::option::Option<T> as FromResidual<Yeet<()>>>
<std::option::Option<T> as FromResidual>
For more information about this error, try `rustc --explain E0277`.
What is the canonical error message, the one from the error code index page or the one, the compiler produces?
Your function clear returns Option<String> but the function conn.sscan("my_set").await?; returns a Result. You cannot use ? to propagate the result because that doesn't match the return type of clear(&self) -> Option<String>.
You will need explicitly handle the Result or convert it to an Option<String>. You could also try adding .ok()? per the compiler hint and see what that gets you.
Whatever you pick the important thing is just to make sure that the return type matches what your ? operator is unwrapping.
Yes, your interpretation is correct, although to be pedantic the error says the opposite:
"If an async function returns Option then the ? operator can only be applied to expressions that has the type Option, and not Result".
And if you ask why on earth this has error code E0277? Well, this is because in order to be propagated using ? a type has to implement the (experimental) Try trait with some combination of type parameters and associated types corresponding to some other combination of the return type of the function. So, in essence, an incompatible type in ? boils down to an unsatisfied trait bound. But unless you're interested in the inner workings of ?, this is not really important.
I'm trying to get started with [imgui ] for Rust (along with [glutin] and [winit]), and I'm working on creating the event loop ([glutin]). To do this, I'm calling event_loop.run_return() (not run() since I want it to return control once the UI is closed).
According to the docs (Ctrl+Q in CLion), the return type of run_return() is i32 (an integer):
winit::platform::run_return impl<T> EventLoopExtRunReturn for EventLoop<T>
fn run_return<F>(&mut self, event_handler: F) -> i32 where F: FnMut(Event<'_, Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow),
Initializes the winit event loop.
...
When I look at the source, it show the exact same (an i32):
fn run_return<F>(&mut self, event_handler: F) -> i32
I want to log what this returns (I'm using [tracing]), so I tried to store it as a variable and then print it:
let exit_code = ui_system
.event_loop
.run_return(event_loop_run);
drop(_run_span_entered); //Ignore, tracing
info!("exit_code: {exit_code}");
This errors on the info!(), because () doesn't implement std::fmt::Display
This is pointing at {exit_code}, which is most definitely not (). Also note how CLion infers the type of exit_code to be i32.
If I try to force the type of exit_code, then the info!() is happy, but now the variable definition errors out:
mismatched types [E0308] expected `i32`, found `()`
Unless I'm going crazy, this is clearly wrong, because the function definition says it must return an i32, but yet the compiler somehow thinks it isn't?
cargo build shows the same thing:
error[E0308]: mismatched types
--> src\main.rs:60:25
|
60 | let exit_code:i32 = ui_system
| ___________________---___^
| | |
| | expected due to this
61 | | .event_loop
62 | | .run_return(event_loop_run);
| |___________________________________^ expected `i32`, found `()`
In the previous version of winit, run_return() did return ().
I suspect that your Cargo.toml specifies 0.26 (or earlier) but CLion is somehow incorrectly presenting you with documentation for 0.27.
I want to get a length of a string which I've split:
fn fn1(my_string: String) -> bool {
let mut segments = my_string.split(".");
segments.collect().len() == 55
}
error[E0282]: type annotations needed
--> src/lib.rs:3:14
|
3 | segments.collect().len() == 55
| ^^^^^^^ cannot infer type for type parameter `B` declared on the associated function `collect`
|
= note: type must be known at this point
Previous compiler versions report the error:
error[E0619]: the type of this value must be known in this context
--> src/main.rs:3:5
|
3 | segments.collect().len() == 55
| ^^^^^^^^^^^^^^^^^^^^^^^^
How can I fix this error?
On an iterator, the collect method can produce many types of collections:
fn collect<B>(self) -> B
where
B: FromIterator<Self::Item>,
Types that implement FromIterator include Vec, String and many more. Because there are so many possibilities, something needs to constrain the result type. You can specify the type with something like .collect::<Vec<_>>() or let something: Vec<_> = some_iter.collect().
Until the type is known, you cannot call the method len() because it's impossible to know if an unknown type has a specific method.
If you’re purely wanting to find out how many items there are in an iterator, use Iterator.count(); creating a vector for the purpose is rather inefficient.
I have a piece of code like this:
use std::cell::RefCell;
use std::rc::Rc;
struct A(bool);
impl A {
fn get_ref(&self) -> &Rc<RefCell<bool>> {
&Rc::new(RefCell::new(self.0))
}
fn copy_ref(&self) -> &Rc<RefCell<bool>> {
Rc::clone(self.get_ref())
}
}
fn main() {
let a = A(true);
a.copy_ref();
}
and I received warning complaining about the Rc::clone function not getting a reference:
error[E0308]: mismatched types
--> src/main.rs:12:9
|
12 | Rc::clone(self.get_ref())
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found struct `std::rc::Rc`
|
= note: expected type `&std::rc::Rc<std::cell::RefCell<bool>>`
found type `std::rc::Rc<std::cell::RefCell<bool>>`
I have been working on this all night but I cannot get it to work. The method get_ref is already typed as returning &Rc<RefCell<bool>>, but why would the compiler give the error?
The error is not talking about the argument you put into Arc::clone(), but the whole expression Rc::clone(...) which has a different type (Rc<...>) than the return type of your function (&Rc<...>).
If you were passing a wrong argument to Rc::clone, it would like look this:
--> src/main.rs:13:19
|
13 | Rc::clone(false)
| ^^^^^ expected reference, found bool
|
= note: expected type `&std::rc::Rc<_>`
found type `bool`
So the naive way to fix the type error is to write &Rc::clone(...) instead. Then the last expression of your function has the same type as your function's declared return type. But as you will notice, you will get other errors afterwards.
Let's take a step back to see that your approach is flawed here. For the most important point, please see "Is there any way to return a reference to a variable created in a function?". Spoiler: you really don't want to. So constructs like your get_ref() just don't make sense, as you return a reference to a variable you create inside your function (a variable of type Rc).
In your case the direct solution is probably pretty simple: just remove the reference. Rc<T> is already a pointer/reference type, so there is no need (in general) to have a reference to it.
However, since you are using Rc, you are probably interested in reference counting. So in that case, you probably shouldn't create a new Rc every time the function is called. Otherwise you could end up with a bunch of Rcs with reference count 1, which is not really the point. So instead, your type A should already store an Rc<RefCell<bool>>.
But all I'm doing here is guessing what you actually want to do which is not clear from your question. Maybe you can ask a different question, or add the information to this question, or explain this in the comments.
I encountered a very confusing error message from the Rust compiler when using the match statement.
enum Name {
Known,
}
fn unreachable_pattern(n: Name) -> usize {
use Name::*;
match n {
Unknown => 1,
Known => 1,
}
}
The Rust compiler complains about an unreachable pattern:
error[E0001]: unreachable pattern
--> src/main.rs:10:9
|
10 | Known => 1,
| ^^^^^ this is an unreachable pattern
|
note: this pattern matches any value
--> src/main.rs:9:9
|
9 | Unknown => 1,
| ^^^^^^^
To a human, the real error is that Unknown is missing from the definition of Name, which is easier to spot when you do not have 40 other variants already.
This is actually a known issue at the moment; it is not a bug proper, but rather a quality of implementation issue.
The issue boils down to irrefutable matches, i.e.:
match variable {
1 => 2,
i => 2 * i
}
Here i is an irrefutable match, meaning it always matches, no matter the value of variable.
Well, we have the same issue with that weird report: because Unknown is unknown, it becomes a name for a variable in an irrefutable match! It is unintended, of course, but it makes perfect sense for the compiler.
The good news is that the compiler starts complaining as soon as the next attempted match, so you can easily find out which match is irrefutable.
A style-lint is expected which would help in this issue, it would report Unknown to be an improperly capitalized variable thus underlining that the compiler does not see it as an enum variant.
There are plenty of variations for this bug (see the duplicates), it might also be caused by improperly importing an enum for example and thus not having its variants in scope.