How to resolve expected `:`, found keyword `self`? - rust

I'm learning to write iterators in Rust but am hitting an "expected colon" issue where I would not expect a colon to even make sense. Maybe it has to do with lifetimes? References? I tried making a regular function that returns the same data in the same way and it worked (or at least got past this error message) so it appears to be special to the Iterator trait... but I can't work out why.
struct LogEntry;
pub struct LogIter<'a> {
index0: bool,
first: LogEntry,
iter: ::std::slice::Iter<'a, LogEntry>,
}
impl<'a> Iterator for LogIter<'a> {
type Item = &'a LogEntry;
fn next(&mut self) -> Option<Self::Item> {
self.index0 = false;
match self.index0 {
true => Some(&'a self.first),
false => self.iter.next(),
}
}
}
It is meant to return first and then iterate normally but I cannot figure out why or how I could possibly fit a colon in here.
error: expected `:`, found keyword `self`
--> src/lib.rs:14:30
|
14 | true => Some(&'a self.first),
| ^^^^ expected `:`

Your question is solved by pointing out that &'a foo isn't a valid expression. It doesn't make sense to specify a lifetime when taking a reference as the compiler will automatically ensure the correct lifetimes.
You want to use Some(&self.first).
Your problem is addressed by How do I write an iterator that returns references to itself?.

Related

Iterator that owns another iterator and creates items with generic lifetime

I want to make an iterator that owns another iterator and gives items based on that other iterator. Originally, the inner iterator is formed from the result of a database query, it gives the raw data rows as arrived from the DB. The outer iterator takes items of the inner iterator and puts them into a struct that is meaningful within my program. Because different software versions store the same data in different database table structures, I have a parser trait that takes a row and creates a structure. My outer iterator takes two parameters for creation: the iterator for the DB rows and an object which implements how to parse the data.
But I run into a lifetime error which I don't really see the reason of, and following the compiler's hints only lead me in circles. I literally follow the compiler's advice and getting back to the same problem. I tried to minic the code and bring it to a minimal form to reproduce the same compiler errors I'm getting. I'm not entirely sure if it could be minimized further, but I also wanted it to resemble my real code.
Here is the sample:
struct Storeroom<'a> {
storeroom_id: i64,
version: &'a str
}
trait StoreroomParser {
fn parse(&self, row: Row) -> Result<Storeroom, Error>;
}
struct StoreroomParserX;
impl StoreroomParser for StoreroomParserX {
fn parse(&self, row: Row) -> Result<Storeroom, Error> {
Ok(Storeroom { storeroom_id: row.dummy, version: "0.0.0"})
}
}
struct StoreroomIterator {
rows: Box<dyn Iterator<Item = Row>>,
parser: Box<dyn StoreroomParser>
}
impl StoreroomIterator {
fn new() -> Result<Self, Error> {
let mut rows: Vec<Row> = vec![];
rows.push(Row { dummy: 4});
rows.push(Row { dummy: 6});
rows.push(Row { dummy: 8});
let rows = Box::new(rows.into_iter());
let parser = Box::new(StoreroomParserX {});
Ok(Self {rows, parser})
}
}
impl Iterator for StoreroomIterator {
type Item<'a> = Result<Storeroom<'a>, Error>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(nextrow) = self.rows.next() {
Some(self.parser.parse(nextrow))
}
else {
None
}
}
}
During my first attempt, the compiler suggested to add a lifetime annotation to the Item type declaration, because it uses a struct that requires a lifetime. But this resulted in the following error:
error[E0658]: generic associated types are unstable
--> src/main.rs:59:5
|
59 | type Item<'a> = Result<Storeroom<'a>, Error>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
error[E0195]: lifetime parameters or bounds on type `Item` do not match the trait declaration
--> src/main.rs:59:14
|
59 | type Item<'a> = Result<Storeroom<'a>, Error>;
| ^^^^ lifetimes do not match type in trait
Here's the sample code on Playground.
When I tried to mitigate this by moving the lifetime annotation to the impl block instead, I provoked the following error I can't progress from:
error: lifetime may not live long enough
--> src/main.rs:61:13
|
56 | impl<'a> Iterator for StoreroomIterator<'a> {
| -- lifetime `'a` defined here
...
59 | fn next(&mut self) -> Option<Self::Item> {
| - let's call the lifetime of this reference `'1`
60 | if let Some(nextrow) = self.rows.next() {
61 | Some(self.parser.parse(nextrow))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
Playground.
I've been stuck on this problem for about a week now. Do you have any ideas how to resolve these errors? I'm also thinking that I should probably just use map() on the rows with whatever closure it takes to properly convert the data, but at this point it would definitely feel like a compromise.
So you say you force version to be 'static with Box::leak(). If so, you can can just remove the lifetime parameter entirely:
struct Storeroom {
storeroom_id: i64,
version: &'static str
}
playground
You also mention that the compiler "forces" you to Box<dyn> rows and parser. You can avoid that by making StoreroomIterator generic over two types for the two members. Only change needed is to take rows in the constructor:
struct StoreroomIterator<R: Iterator<Item = Row>, P: StoreroomParser> {
rows: R,
parser: P
}
impl<R: Iterator<Item = Row>> StoreroomIterator<R, StoreroomParserX> {
fn new(rows: R) -> Result<Self, Error> {
let parser = StoreroomParserX {};
Ok(Self { rows, parser })
}
}
playground
It may be possible to get everything to work with lifetimes as well, but from your incomplete example, it's hard to say exactly. You may want to store a String containing the version in Storeroom and then add a version() method to generate a Version on demand, rather than generating them all up front. But it's hard to say without knowing what this all is for. You may just want to switch to a different library for handling version comparisons.

How to understand closure parameters

I am a beginner in Rust. I tried to write a linked list for practice.
Some sturct code:
type Link<T> = Option<Box<Node<T>>>;
pub struct List<T> {
head: Link<T>,
}
struct Node<T> {
elem: T,
next: Link<T>,
}
Peek function for List:
error code:
pub fn peek(&self) -> Option<&T> {
self.head.map(|ref node| {
&node.elem
})
}
The Rust compiler return: cannot return value referencing function parameter.
The following code is ok:
pub fn peek(&self) -> Option<&T> {
self.head.as_ref().map(|node| {
&node.elem
})
}
So I guess,
The error code is actually an abbreviation of the following code:
self.head.map(|node| {
let ref ref_node = node;
&ref_node.elem
})
Is my guess correct?
More, is there a similar abbreviation in Rust? Or abbreviation rules.
The error “cannot return value referencing function parameter” is sort of a red herring here; it has nothing to do with the fundamental problem, but just happened to be listed first. If you compile the code
type Link<T> = Option<Box<Node<T>>>;
pub struct List<T> {
head: Link<T>,
}
struct Node<T> {
elem: T,
next: Link<T>,
}
impl<T> List<T> {
pub fn peek(&self) -> Option<&T> {
self.head.map(|ref node| &node.elem)
}
}
then you will get two errors, the second of which is the reason this code doesn't work and you needed .as_ref():
error[E0507]: cannot move out of `self.head` which is behind a shared reference
--> src/lib.rs:14:9
|
14 | self.head.map(|ref node| &node.elem)
| ^^^^^^^^^ move occurs because `self.head` has type `Option<Box<Node<T>>>`, which does not implement the `Copy` trait
|
help: consider borrowing the `Option`'s content
|
14 | self.head.as_ref().map(|ref node| &node.elem)
| +++++++++
This error is the one from the root cause; Option::map consumes its input Option, which is not what we want to do here. Option::as_ref solves this by taking an &Option<T> (here, by implicit auto-reference turning self.head into &self.head) and returning a newly created Option<&T>, which can then be consumed by Option::map.
But, I understand that you want to know how the erroneous code produced the “cannot return…” error. Here's how:
We know that self.head is an Option<Box<Node<T>>>.
Calling Option::map() on that type means it expects a function FnOnce(Box<Node<T>>) -> &T.
That is, the closure is acting as a function which is given ownership of a Box<Node<T>>. So, within the closure, node is a local variable that owns the Box.
The body of the closure then attempts to return a reference to a field of the Node inside that box, which is an error E0515 since the box is owned by a local variable and is going to be dropped at the end of the function.
Your ref modifier does not change things, because whether a value is moved into a function is determined by the function's parameter types, not by what kind of pattern/binding the function body uses.
The error code is actually an abbreviation of the following code:
self.head.map(|node| {
let ref ref_node = node;
&ref_node.elem
})
Is my guess correct?
Yes and no. You can expand the code that way. But that's not the “real” code; it's rather that introducing the separate ordinary variable node before a more complex pattern is always valid, for function parameters. It's not something that the compiler does anyway; it's adding trivial code, in the same way that multiplying by 1 doesn't change a number. But, the fact that you can do this without changing the program is a consequence of the fact that function parameters are moved in regardless of what the function itself writes in its parameter patterns.
However, it wouldn't be possible to make your original code work by changing Rust function parameters to work that way. The function which is causing the problem is Option::map() applied to a borrowed struct field; that would always fail regardless of what the function passed to map() does, because Option::map() always consumes the Option given to it.

"Expected associated type, found `u32`" when using the lifetime of a parameter as trait parameter in where bound

I tried to compile this code (Playground):
trait Family<'a> {
type Out;
}
struct U32Family;
impl<'a> Family<'a> for U32Family {
type Out = u32;
}
trait Iterator {
type Item;
fn next<'s>(&'s mut self) -> <Self::Item as Family<'s>>::Out
where
Self::Item: Family<'s>;
}
struct Foo;
impl Iterator for Foo {
type Item = U32Family;
fn next<'s>(&'s mut self) -> <Self::Item as Family<'s>>::Out
where
Self::Item: Family<'s>,
{
0u32 // <-- in real code, this is somehow calculated
}
}
But sadly, it results in this error:
error[E0308]: mismatched types
--> src/main.rs:28:9
|
24 | fn next<'s>(&'s mut self) -> <Self::Item as Family<'s>>::Out
| ------------------------------- expected `<U32Family as Family<'s>>::Out` because of return type
...
28 | 0u32
| ^^^^ expected associated type, found u32
|
= note: expected type `<U32Family as Family<'s>>::Out`
found type `u32`
I really don't understand why. Obviously, in this code snippet, <U32Family as Family<'s>>::Out is exactly u32. But Rust seems to think that it's not always the same. Why? And how can I make it compile?
Some notes:
There are a bunch of similar situations where a similar error occurs, but I think this is different from everything I've seen so far.
I cannot use type Out: for<'a> Family<'a>;. So that's not a workaround that works for me.
If I remove the lifetime parameter of Family, everything works.
If I replace Family<'s> with Family<'static> in the function signature, everything works.
EDIT: I can work around this problem by adding:
impl U32Family {
fn from<'a>(v: u32) -> <Self as Family<'a>>::Out {
v
}
}
Then I can just say Self::Item::from(0u32) in the body of next(). (Playground)
I think it's clear why the error in next() is gone: U32Family::from always takes u32 as argument. Hardcoded. Never changing. The bigger question about this workaround is: why does the from() method compile fine? So in from() the compiler somehow knows that <Self as Family<'a>>::Out is always u32, but if I try the same in next(), somehow the compiler doesn't understand that <Self::Item as Family<'s>>::Out is u32. Now I'm even more confused.
EDIT2: first, I suspected that specialization is the problem. For example, you might write:
impl Family<'static> for U32Family {
type Out = char;
}
Then of course, the compiler would be right in assuming that u32 is not always the same as <Self::Item as Family<'s>>::Out for any 's. However, I think this is not the problem.
First of all, impls that can be specialized need to be marked with the default keyword. I did not do that, so I should be able to assume the associated type is in fact u32 (the RFC talks about something very similar). But additionally, specialization based on lifetimes is not allowed.
So by now I tend to think this is a compiler error. But I'd love to get another answer!
I think the problem is that it is a "coincidence" that <Self::Item as Family<'s>>::Out is u32 for all 's. The compiler can prove it for any 's you want, but it can't even express the concept that it is true for all 's.
The work-around you have found is the right approach: add a method to U32Family which converts a u32 into a <Self as Family<'a>>::Out. The body of the method is entirely inside the scope of 'a, so the compiler can prove that the conversion is type-correct for that 'a, and therefore that the method is type-correct. Then, at the call-site, you're telling the compiler to use its knowledge about the method.
struct U32Family;
...
impl Iterator for Foo {
type Item = U32Family;
So next() must return Option<U32Family>, whose only possible values are None and Some(U32Family{})
You probably want Item = <U32Family as Family<'static>::Out which fixes this issue but creates some lifetime issues. (The Item needs a lifetime because Family has one, but you only accept a lifetime on next())

How to match against a &'static str in Rust

I am a Rust beginner and I can't solve this type problem. I have tried replacing &name with name, but the error "pattern &_ not covered" occurred.
fn get_project(name: &'static str) {
match &name {
"hi" => {},
}
}
fn main() {
let project = get_project("hi");
}
Compiler error:
error[E0308]: mismatched types
--> <anon>:3:9
|
3 | "hi" => {},
| ^^^^ expected &str, found str
|
= note: expected type `&&str`
= note: found type `&'static str`
String literals – like "hi" – have the type &'static str. So if you already have a &str, you don't need to add the &:
fn get_project(name: &str) {
match name {
"hi" => {},
_ => {}, // matches have to be exhaustive
}
}
I also added a default case, because matches in Rust need to be exhaustive: they need to cover all possible cases.
Maybe you noticed, that I also removed the 'static from the argument list. If you want to read about some lifetime stuff, go ahead. Else, stop reading here, because it's possibly confusing and not that important in this case.
In this function there is no need to restrict the lifetime of the given argument to 'static. Maybe you also want to pass in string slices that are borrowed from a String:
let user_input = read_user_input(); // type `String`
get_project(&input);
The code above only works when you remove the 'static from the argument. Once removed, the function is equivalent to:
fn get_project<'a>(name: &'a str) { ... }
This means that the function is generic over a lifetime 'a. The function says: given any lifetime 'a, you can give me a string with said lifetime and I am able to do my thing. Which is true. If the function wouldn't be able to do it for any lifetime, the compiler would complain ;-)
In your example, name doesn't need to have a static lifetime. Because you only use name inside your function, name doesn't need to have an extended lifetime. Check out the strings chapter of The Rust Programming Language. To match a &str with a &'static str you don't need &, just the variable itself is enough.
pub fn get_project(name: &str) {
match name {
"hi" => println!("I found hi!"),
_ => println!("Nothing match"),
}
}
fn main() {
get_project("hi");
get_project("42");
}

Can't figure out return type of this Rust function that returns Iter?

I have this small Rust function:
pub fn factor(input_array: &mut [i32]) {
let x = input_array
.iter()
.filter(|&x| x % 2 == 0);
x
}
When I run this via cargo run I get this error:
Compiling gettingrusty v0.0.1 (file:///home/lowks/src/rust/gettingrusty)
src/functional.rs:22:9: 22:10 error: mismatched types:
expected `()`,
found `core::iter::Filter<core::slice::Iter<'_, i32>, [closure#src/functional.rs:21:21: 21:36]>`
(expected (),
found struct `core::iter::Filter`) [E0308]
src/functional.rs:22 x
^
src/functional.rs:22:9: 22:10 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error
Could not compile `gettingrusty`.
I tried a few return types such as slice::Iter<i32> and core::slice::Iter<i32> but seems like all of them are wrong. What should be the return type of my function?
Under normal circumstances, you could just copy+paste the found part of the error message. There are two problems with that in this particular case.
First, core isn't directly accessible. Various items are exposed by the standard library libstd, but are actually defined by libcore. Basically, the standard library is the public interface you are meant to use to access these items, but the compiler doesn't know that. Typically, you work around this by just replacing core::* with std::*.
The second problem is that the type includes a closure, and closures cannot be named. The simplest solution is to just not use a closure at all; you aren't capturing anything, anyway.
Doing that and just fixing the compile errors as they come up leads to:
pub fn factor(input_array: &mut [i32])
-> std::iter::Filter<std::slice::Iter<i32>, fn(&&i32) -> bool> {
fn even(x: &&i32) -> bool { **x % 2 == 0 }
let x = input_array
.iter()
.filter(even as for<'r> fn(&'r &_) -> _);
x
}
Your function returns a Filter object, so its actual return type is Filter<_, _> for some generic arguments. That’s fine, but chances are, you’ll want to hide all the implementation details from the type signature and just say that your function returns some iterator. Unfortunately, there is no (as of today) easy way to do this.
The pattern that seems to be rather common is to use a newtype wrapper. The problem with this is that writing the wrapper is a little bit more difficult than one might expect, e.g. one will have to deal with lifetimes explicitly.
Here is a complete example:
use std::iter::Filter;
use std::slice::Iter;
struct FactorResult<'a, T: 'a>(Filter<Iter<'a, T>, fn(&&T) -> bool>);
impl<'a, T> Iterator for FactorResult<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> { self.0.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
}
fn factor(input_array: &[i32]) -> FactorResult<i32> {
fn even(x : &&i32) -> bool { **x % 2 == 0 }
FactorResult(input_array.iter().filter(even))
}
fn main () {
for x in factor(&[1,2,3,4]) {
println!("{}", x);
}
}
The factor function returns a FactorResult which is just a wrapper that hides the actual underlying type.
The only thing the user knows about FactorResult is that it is an Iterator. The implementation of the trait is trivial, but I had to spell it out.
I had to replace the closure with the function. This is because here Rust does not perform any allocations, so it needs to know the size of FactorResult<T>, but the type of the closure is anonymous so there is no way to refer to it. One could use a closure but the whole thing would have to be boxed in this case.

Resources