I am attempting template some functions and finding it difficult to template functions returning Iterators. They occur as syntax errors
struct A;
impl A {
fn x(&self) -> impl Iterator<Item = String> {
todo!()
}
}
The syntax error is:
Compiling playground v0.0.1 (/playground)
error[E0277]: `()` is not an iterator
--> src/lib.rs:3:20
|
3 | fn x(&self) -> impl Iterator<Item = String> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
|
= help: the trait `Iterator` is not implemented for `()`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error
The standard library's Empty::new() is available to provide a template default. However, the standard approach is to use the provided constructor function: std::iter::empty()
struct A;
impl A {
fn x(&self) -> impl Iterator<Item = String> {
std::iter::empty()
}
}
The reason that this doesn't work is that todo!() returns ! (aka never). Since ! cannot have a value, it can be reconciled to any other type; that is, it's concrete type is inferred based on assignment, similar to a generic return type, T. But impl Iterator isn't concrete either, so each one is relying on the other for type inferrence, creating a kind of circular reference.
You can fix this by making the body a concrete iterator type, as in George's answer, which I won't duplicate here. Alternatively you can make the return type concrete. For example:
use std::iter::Empty;
fn x(&self) -> Empty<String> {
std::iter::empty()
}
Type inference can be convenient and can reduce the amount of noise in type annotations, but you need to provide sufficient information, so the type can be inferred in one direction or the other.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With