How do I tell Rust that something implements a trait? [duplicate] - rust

This question already has answers here:
What is the correct way to return an Iterator (or any other trait)?
(2 answers)
Closed 3 years ago.
I'm trying to write a generic function that returns an iterator.
fn one_to_ten<T: Add>() -> std::iter::Iterator<Item = T> {
(1..5).chain(5..=10)
}
It's generic because it needs to work for u8 through u128, and preferably also i8 through i128, for the following code:
let mut sum: u64 = 0;
for x in one_to_ten() {
sum += x;
}
Unfortunately, Rust complains:
= help: the trait std::marker::Sized is not implemented for (dyn std::iter::Iterator<Item = T> + 'static)
error[E0277]: the size for values of type dyn std::iter::Iterator<Item = _> cannot be known at compilation time
and
error[E0308]: mismatched types
expected trait std::iter::Iterator, found struct std::iter::Chain
I'm out of my depth here. Rust seems to think I'm trying to implement a dynamically dispatched function, when I'm trying to implement a generic one instead. (And, for some reason, my chained iterator isn't accepted as an iterator – my guess is that I'm specifying a type instead of a trait, but std::iter::Iterator is a trait, not a type.)
What should my code look like?

Traits are unsized so you cannot return a value of trait type. Instead you must return a value of a type that implements that trait:
fn one_to_ten<T: Add>() -> impl std::iter::Iterator<Item = T> {
(1..5).chain(5..=10)
}
Unfortunately that brings another issue, that the (1..5) code builds a range of integers, not of T. You can fix that with a custom trait, as the std::iter::Step is still unstable.
Something like this (playground):
pub trait MyRange: Sized {
type Iter: std::iter::Iterator<Item = Self>;
fn new(a: i32, b: i32) -> Self::Iter;
fn new_incl(a: i32, b: i32) -> Self::Iter {
Self::new(a, b + 1)
}
}
impl MyRange for i8 {
type Iter = std::ops::Range<Self>;
fn new(a: i32, b: i32) -> Self::Iter {
(a as i8 .. b as i8) //check overflow?
}
}
pub fn one_to_ten<T: Add + MyRange>() -> impl std::iter::Iterator<Item = T> {
T::new(1, 5).chain(T::new_incl(5, 10))
}
And then implement the MyRange trait for every integer type you need.

Related

Lifetimes for generalizing trait implementation from &T to AsRef<T>

I have some problems generalizing a trait working for &str to other string types (e.g. Rc<str>, Box<str>,String).
First of all my example function should work for:
assert_eq!(count("ababbc", 'a'), 2); // already working
assert_eq!(count(Rc::from("ababbc"), 'a'), 2); // todo
assert_eq!(count("ababbc".to_string(), 'a'), 2); // todo
This is the working code, which makes the first test run:
pub trait Atom: Copy + Eq + Ord + Display + Debug {}
impl Atom for char {}
pub trait Atoms<A, I>
where
I: Iterator<Item = A>,
A: Atom,
{
fn atoms(&self) -> I;
}
impl<'a> Atoms<char, std::str::Chars<'a>> for &'a str {
fn atoms(&self) -> std::str::Chars<'a> {
self.chars()
}
}
pub fn count<I, A, T>(pattern: T, item: A) -> usize
where
A: Atom,
I: Iterator<Item = A>,
T: Atoms<A, I>,
{
pattern.atoms().filter(|i| *i == item).count()
}
To make the next tests run, I changed the signature of count and Atoms in following way:
pub trait Atoms<'a, A, I>
where
I: Iterator<Item = A> + 'a,
A: Atom,
{
fn atoms<'b>(&'b self) -> I
where
'b: 'a;
}
impl<'a, S> Atoms<'a, char, std::str::Chars<'a>> for S
where
S: AsRef<str> + 'a,
{
fn atoms<'b>(&'b self) -> std::str::Chars<'b>
where
'b: 'a,
{
self.as_ref().chars()
}
}
but now the function count does not compile any more:
pub fn count<'a, I, A, T>(pattern: T, item: A) -> usize
where
A: Atom,
I: Iterator<Item = A> + 'a,
T: Atoms<'a, A, I>,
{
pattern.atoms().filter(|i| *i == item).count()
}
Playground-Link
The compiler error is: the parameter type 'T' may not live long enough ... consider adding an explicit lifetime bound...: 'T: 'a'. This is not completely understandable for me, so I tried to apply the help T: Atoms<'a, A, I> + 'a. Now the error is: 'pattern' does not live long enough ... 'pattern' dropped here while still borrowed.
Since the latter error also occurs without implementations of Atoms and by just replacing the function body by pattern.atoms();return 1; I suspect that the type signature of Atoms is not suitable for my purpose.
Has anybody a hint what could be wrong with the type signature of Atoms or count?
trait Atoms<'a, A, I> where I: Iterator<Item = A> + 'a ...
By writing this, you're requiring the iterator to outlive the lifetime 'a. Since 'a is part of the trait's generic parameters, it must be a lifetime that extends before you start using (implicitly) <String as Atoms<'a, char, std::str::Chars>>::atoms. This directly contradicts the idea of returning a new iterator object, since that object did not exist before the call to atoms().
Unfortunately, I'm not sure how to rewrite this so that it will work, without generic associated types (a feature not yet stabilized), but I hope that at least this explanation of the problem helps.
I hope I clarify at least some parts of the problem. After doing some internet research on HRTBs and GATs I come to the conclusion that my problem is hardly solvable with stable rust.
The main problem is that one cannot
have a trait with different lifetime signature than its implementations
keep lifetimes generic in a trait for later instantiation in the implementation
limit the upper bound of a results lifetime if it is owned
I tried several approaches to but most evolve to fail:
at compiling the implementation (because the implementations lifetimes conflict with those of the trait)
at compiling the caller of the trait because a compiling implementation limits the lifetimes in a way, that no object can satisfy them.
At last I found two solutions:
Implement the trait for references
the function atoms(self) does now expect Self and not &Self
Atoms<A,I> is implemented for &'a str and &'a S where S:AsRef<str>
This gives us control of the lifetimes of the self objects ('a) and strips the lifetime completely from the trait.
The disadvantage of this approach is that we have to pass references to our count function even for smart references.
Playground-Link
use std::fmt::Display;
use std::fmt::Debug;
pub trait Atom: Copy + Eq + Ord + Display + Debug {}
impl Atom for char {}
pub trait Atoms<A, I>
where
I: Iterator<Item = A>,
A: Atom,
{
fn atoms(self) -> I;
}
impl<'a> Atoms<char, std::str::Chars<'a>> for &'a str {
fn atoms(self) -> std::str::Chars<'a> {
self.chars()
}
}
impl<'a, S> Atoms<char, std::str::Chars<'a>> for &'a S
where
S: AsRef<str>,
{
fn atoms(self) -> std::str::Chars<'a> {
self.as_ref().chars()
}
}
pub fn count<I, A, T>(pattern: T, item: A) -> usize
where
A: Atom,
I: Iterator<Item = A>,
T: Atoms<A, I>,
{
pattern.atoms().filter(|i| *i == item).count()
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use super::*;
#[test]
fn test_example() {
assert_eq!(count("ababbc", 'a'), 2);
assert_eq!(count(&"ababbc".to_string(), 'a'), 2);
assert_eq!(count(&Rc::from("ababbc"), 'a'), 2);
}
}
Switch to Generic Associated Types (unstable)
reduce the generic type Atoms<A,I> to an type Atoms<A> with an generic associated type I<'a> (which is instantiable at implementations)
now the function count can refer to the lifetime of I like this fn atoms<'a>(&'a self) -> Self::I<'a>
and all implementations just have to define how the want to map the lifetime 'a to their own lifetime (for example to Chars<'a>)
In this case we have all lifetime constraints in the trait, the implementation can consider to map this lifetime or ignore it. The trait, the implementation and the call site are concise and do not require references or helper lifetimes.
The disadvantage of this solution is that it is unstable, I do not know whether this means that runtime failures would probably occur or that api could change (or both). You will have to activate #![feature(generic_associated_types)] to let it run.
Playground-Link
use std::{fmt::Display, str::Chars};
use std::{fmt::Debug, rc::Rc};
pub trait Atom: Copy + Eq + Ord + Display + Debug {}
impl Atom for char {}
pub trait Atoms<A>
where
A: Atom,
{
type I<'a>: Iterator<Item = A>;
fn atoms<'a>(&'a self) -> Self::I<'a>;
}
impl Atoms<char> for str
{
type I<'a> = Chars<'a>;
fn atoms<'a>(&'a self) -> Chars<'a> {
self.chars()
}
}
impl <S> Atoms<char> for S
where
S: AsRef<str>,
{
type I<'a> = Chars<'a>;
fn atoms<'a>(&'a self) -> Chars<'a> {
self.as_ref().chars()
}
}
pub fn count<A, S>(pattern: S, item: A) -> usize
where
A: Atom,
S: Atoms<A>,
{
pattern.atoms().filter(|i| *i == item).count()
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use super::*;
#[test]
fn test_example() {
assert_eq!(count("ababbc", 'a'), 2);
assert_eq!(count("ababbc".to_string(), 'a'), 2);
assert_eq!(count(Rc::from("ababbc"), 'a'), 2);
}
}

"borrowed value does not live long enough", but why do we need it to live so long? [duplicate]

This question already has answers here:
How do I write the lifetimes for references in a type constraint when one of them is a local reference?
(1 answer)
Borrowed value does not live long enough when iterating over a generic value with a lifetime on the function body
(1 answer)
How does "for<>" syntax differ from a regular lifetime bound?
(1 answer)
Closed 4 years ago.
There are lots of similar questions, but I couldn't find the answer to my exact question.
In my Rust code, I have a generic type and want to implement a method that takes a reference to another instance of the that type, and then another method that consumes its argument but does exactly the same thing as the first one:
#[derive(Debug, PartialEq, Clone)]
pub struct Wrapper<T> {
v: T,
}
impl<T> Wrapper<T> {
pub fn f_ref(&self, _other: &Wrapper<T>) { /* ... */ }
pub fn f_consume(&self, other: Wrapper<T>) {
self.f_ref(&other)
}
}
It compiles just fine.
Now I want to do basically the same, but while implementing a trait. First, the function that takes a reference:
use std::ops::AddAssign;
impl<'a, T> AddAssign<&'a Wrapper<T>> for Wrapper<T> where T: AddAssign<&'a T> {
fn add_assign(&mut self, other: &'a Wrapper<T>) {
self.v += &other.v;
}
}
#[test]
fn test() {
let mut a = Wrapper { v: 1_i32 };
let b = Wrapper { v: 2 };
a += &b;
drop(b);
assert_eq!(a, Wrapper { v: 3 });
}
It works, too.
Now I want to implement AddAssign for Wrapper<T> based on the implementation of AddAssign<&Wrapper<T>> that I already have. I understand that if T has references in it, it will cause trouble, so I make sure it has 'static lifetime. I'm OK with it: in my program, I expect T to be something like an owned matrix of numbers wrapped in some custom struct.
impl<'a, T> AddAssign for Wrapper<T> where T: 'static + AddAssign<&'a T>, Wrapper<T>: 'static {
fn add_assign(&mut self, other: Wrapper<T>) {
*self += &other;
}
}
And it fails. The compiler says that other must stay valid after we used a reference to it to in a += expression. But when we used such a reference in the test() function above and dropped b there (which played the role of other here) and used the result later, the compiler agreed it's OK. Why?
I suspect that I need to specify some additional trait bounds for T or Wrapper<T> but don't understand what these bound should be.
Code in playground.

How do I implement std::ops::Index to mutate the value being indexed? [duplicate]

This question already has answers here:
Implementing Index trait to return a value that is not a reference
(2 answers)
Closed 5 years ago.
I want to learn how to use the Index trait for my toy roguelike but can't even get it to work in a useless, dummy scenario.
use std::ops::Index;
// Dummy struct that wraps i32
#[derive(Clone, Copy, Debug)]
pub struct Integer {
pub val: i32,
}
impl Integer {
fn new(num: i32) -> Self {
Integer { val: num }
}
}
// Using the index operator on an Integer should add the index to the Integer's value.
// let i = Integer::new(20);
// i[20];
// The above code should make it so i.val == 40
impl Index<Integer> for Integer {
type Output = i32;
// The error is in the following line:
fn index(&self, to_add: Integer) -> &Self::Output {
self.val + to_add.val;
}
}
// The code causes an error before it reaches this
fn main() {
let mut i = Integer::new(20);
let mut n = Integer::new(30);
println!("i[20] is: {:?}", i[n]);
}
I get this error:
error[E0308]: mismatched types
--> src/main.rs:23:55
|
23 | fn index(&self, to_add: Integer) -> &Self::Output {
| _______________________________________________________^
24 | | self.val + to_add.val;
25 | | }
| |_____^ expected &i32, found ()
|
= note: expected type `&i32`
found type `()`
I don't really know what I'm talking about but I guess that the value dies before it reaches the end of the function or something like that? I don't yet fully understand lifetimes.
I know this looks like a "NO IDEA WHAT IM DOING FIX PLS" question, but I'd love to know what I'm doing wrong here so I can learn from it.
Editor's note: This answer applied to the original question before the OP completely changed it. It is no longer applicable to the posted question.
The Index documentation says, emphasis mine:
The Index trait is used to specify the functionality of indexing operations like container[index] when used in an immutable context.
You are attempting to mutate the value, which is simply not possible. You can also tell this from the signature of index:
pub trait Index<Idx>
where
Idx: ?Sized,
{
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
There's no mut anywhere here; you cannot "implement" a trait with a completely different signature! You also cannot change the type of one of the arguments (in this case, self).
Bluntly put, Index is the wrong trait to use. Additionally, idiomatic Rust users would be really upset if you did implement the code this way; we generally aren't of the "reuse an operator for a completely different meaning" crowd.
Instead, this should just be a function with a name:
impl Integer {
fn increment(&mut self, to_add: i32) {
self.val += to_add;
}
}
Alternatively, you could implement DerefMut:
use std::ops::{Deref, DerefMut};
impl Deref for Integer {
type Target = i32;
fn deref(&self) -> &Self::Target { &self.val }
}
impl DerefMut for Integer {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.val }
}
And then use it like
let mut i = Integer::new(20);
*i += 20;
println!("i[20] is: {:?}", i);

How to use recursive associated types in functions?

I am trying to write a function that can descent into any kind of Value and inform a Delegate about the similarities it observes. The idea is to make this work across all kinds of Json/Yaml/YouNameIt values, generically.
Here is an MVCE to trigger the issue (playground link):
pub trait Value: PartialEq<Self> {
type Item;
type Key;
fn items<'a>(&'a self) -> Option<Box<Iterator<Item = (Self::Key, &'a Self::Item)> + 'a>>;
}
pub trait Delegate<'a, V> {
fn something(&mut self, _v: &'a V) {}
}
pub fn diff<'a, V, D>(l: &'a V, d: &'a mut D)
where V: Value,
<V as Value>::Item: Value,
D: Delegate<'a, V>
{
d.something(l);
let v = l.items().unwrap().next().unwrap();
d.something(v.1);
}
struct Recorder;
impl<'a, V> Delegate<'a, V> for Recorder {}
#[derive(PartialEq)]
struct RecursiveValue;
impl Value for RecursiveValue {
type Key = usize;
type Item = RecursiveValue;
fn items<'a>(&'a self) -> Option<Box<Iterator<Item = (Self::Key, &'a Self::Item)> + 'a>> {
None
}
}
fn main() {
let v = RecursiveValue;
let mut r = Recorder;
diff(&v, &mut r);
}
When attempting to compile the code, the following error is produced:
error[E0308]: mismatched types
--> <anon>:19:17
|
19 | d.something(v.1);
| ^^^ expected type parameter, found associated type
|
= note: expected type `&'a V`
= note: found type `&<V as Value>::Item`
I'm trying to say that the associated Item type is of type V too. Is there a way to make such an algorithm work generically?
The answer lies at the very bottom of the Associated Types chapter of the Rust Book.
When using a generic type in a bound, as in V: Value, it is possible to constrain one or several of its associated types to specific types by using the Generic<AssociatedType = SpecificType> syntax.
In your case, it means constraining V to Value<Item = V>. This should also obsolete any reason to further constrain V::Item since the bounds to V are naturally available.
I do encourage you to read the book to help you learn Rust, or at least skim it to know what's available there and be able to refer to it when you have a difficulty.
Here's a further reduced example:
pub trait Value {
type Item;
fn items(&self) -> &Self::Item;
}
pub trait Delegate<V> {
fn something(&mut self, v: &V);
}
pub fn diff<V, D>(l: &V, d: &mut D)
where V: Value,
V::Item: Value,
D: Delegate<V>
{
let v = l.items();
d.something(v);
}
fn main() {}
The important thing to focus on are the restrictions on the generics of diff:
pub fn diff<V, D>(l: &V, d: &mut D)
where V: Value,
V::Item: Value,
D: Delegate<V>
In words, this says:
V can be any type so long as it implements the Value trait.
V::Item can be any type so long as it implements the Value trait.
D can be any type so long as it implements the Delegate<V> trait.
Nowhere in that list of requirements was listed "V and V::Item must be the same". In fact, it's a feature that they are not required to be the same.
In this reduction, another solution would be to say D: Delegate<V::Item>. However, that wouldn't apply to the slightly larger reproduction:
pub fn diff<V, D>(l: &V, d: &mut D)
where V: Value,
V::Item: Value,
D: Delegate<V::Item>
{
d.something(l);
let v = l.items();
d.something(v);
}
As Matthieu M. has pointed out, you want to specify the associated type of the trait:
pub fn diff<V, D>(l: &V, d: &mut D)
where V: Value<Item = V>,
D: Delegate<V>
For further reading, check out Requiring implementation of Mul in generic function.

No method found when extending the Iterator trait in Rust

I am trying to extend the functionality of the Iterator trait.
My statistics/iter_statistics.rs:
mod iter_statistics {
pub trait IterStatistics: Iterator<Item = f64> {
fn foo(&mut self) -> f64 {
0.0
}
}
impl IterStatistics for Iterator<Item = f64> {}
}
And statistics/mod.rs:
pub use self::iter_statistics::*;
mod iter_statistics;
And finally in my test code I have
use statistics::IterStatistics;
fn main() {
let z: Vec<f64> = vec![0.0, 3.0, -2.0];
assert_eq!(z.into_iter().foo(), 0.0);
}
When I run the test, I get:
error: no method name `foo` found for type `std::vec::IntoIter<f64>` in the current scope
assert_eq!(z.into_iter().foo(), 0.0);
^~~
which is strange to me since the docs for IntoIter<T> say it implements Iterator<Item=T>.
The impl you have written will only apply to trait objects (e.g. &mut Iterator<Item=f64>), not for all types that implement Iterator<Item=f64>. You want to write a generic impl like this:
impl<T: Iterator<Item=f64>> IterStatistics for T {}
Your implementation is backward. When programming in Rust, you have to forget about OO-inheritance and reason in terms of capabilities.
What does trait D: B means in Rust?
This means that D can only be implemented for types that already implement B. It's not inheritance, it's a constraint.
When to use trait D: B then?
The main reason to use this constraint is when you wish to provide a default implementation of D methods that will require associated items (traits, constants, methods) from B.
In general, you do not want to add more constraints than strictly necessary, as your clients may wish to use this trait in ways you did not foresee.
The one exception is when creating a trait as a "bundle of constraints", so that you do not have type T: SomeTrait + SomeOtherTrait + Send for all the methods your are implementing. This "bundle of constraints" should be empty, then; it's not a functional trait after all, just an "alias".
So, how to extend Iterator?
First declare a new trait:
pub trait IterStatistics {
fn foo(&mut self) -> f64;
}
Then implement it for all types already implementing Iterator<Item = f64>:
impl<T> IterStatistics for T
where T: Iterator<Item = f64>
{
fn foo(&mut self) -> f64 {
0.0
}
}

Resources