Cannot create a generic function that uses a literal zero - rust

I am trying to write a Rust function that is similar to the built-in Range, but I want something that will return only X numbers, and return it as a list, which is why I'm trying to make this function:
extern crate num;
use num::Integer;
fn positions<T: Integer>(start: T, step: T, len: T) -> Vec<T> {
(0..len).map(|i| start + step * i).collect()
}
fn main() {
println!("{:?}", positions(10, 2, 10));
}
Except I am getting a compiler error:
error[E0308]: mismatched types
--> src/main.rs:6:9
|
6 | (0..len).map(|i| start + step * i).collect()
| ^^^ expected integral variable, found type parameter
|
= note: expected type `{integer}`
found type `T`
= help: here are some functions which might fulfill your needs:
- .div_floor(...)
- .gcd(...)
- .lcm(...)
- .mod_floor(...)
error[E0308]: mismatched types
--> src/main.rs:6:37
|
6 | (0..len).map(|i| start + step * i).collect()
| ^ expected type parameter, found integral variable
|
= note: expected type `T`
found type `{integer}`

The problem is 0. I'm unclear on the exact rules right now, but let's be general: 0 is of some specific integer type, which may or may not be the same thing as whatever T is. Thus, the compiler can't work out what the type parameter to range is supposed to be.
You can resolve this by using Zero::zero:
fn positions<T: Integer>(start: T, step: T, len: T) -> Vec<T> {
(T::zero()..len).map(|i| start + step * i).collect()
}
This gives the compiler enough leeway to infer that the two arguments to range are of the same type. However, that's still not enough to use Range as an iterator:
error: no method named `map` found for type `std::ops::Range<T>` in the current scope
--> src/main.rs:8:22
|
8 | (T::zero()..len).map(|i| start + step * i).collect()
| ^^^
|
= note: the method `map` exists but the following trait bounds were not satisfied: `T : std::iter::Step`, `&'a T : std::ops::Add`, `std::ops::Range<T> : std::iter::Iterator`
Unfortunately, as of Rust 1.17, the Step trait is unstable, so there's currently no good way to solve this problem using stable Rust.
Using unstable Rust, you can require implementations of Step:
#![feature(step_trait)]
extern crate num;
use num::Integer;
fn positions<T>(start: T, step: T, len: T) -> Vec<T>
where T: Integer + std::iter::Step + Copy,
for<'a> &'a T: std::ops::Add<Output = T>
{
(T::zero()..len).map(|i| start + step * i).collect()
}
fn main() {
println!("{:?}", positions(10, 2, 10));
}
You also need to require that T can be copied (or cloned, if you like) because the implementation of Add and Mul consumes the operands by value, which would mean that start + step * i could only be called once, except it needs to be called multiple times.

Related

From and Into with binary std::ops: cannot infer type for type parameter `T`?

When I do
seq += u64::from(rhs);
Everything works. But I'd prefer the syntax of rhs.into() with that I'm currently getting,
error[E0283]: type annotations needed
--> src/sequence.rs:50:5
|
19 | seq += rhs.into();
| ^^ ---------- this method call resolves to `T`
| |
| cannot infer type for type parameter `T`
|
= note: cannot satisfy `_: Into<u64>`
= note: required because of the requirements on the impl of `AddAssign<_>` for `Sequence`
This .into() syntax normally works. Why doesn't type inference work on binary operators += such that if the LHS only implements AddAssign<u64> the RHS will coerce? And moreover, aside from using from what is the syntax (if possible) to provide this type information to .into that the compiler needs? I've tried things like .into::<u64>(rhs) and that also doesn't work.
I am implementing AddAssign like this,
impl<T: Into<u64>> AddAssign<T> for Sequence {
fn add_assign(&mut self, rhs: T) {...}
}
And From like this,
impl From<Sequence> for u64 {
fn from(seq: Sequence)-> u64 { ... }
}
You have a double Into indirection, probably by mistake. Since your type already implements AddAssign<T> where T: Into<u64>, then there is no need to add .into() to your right-hand member. It should be expected that the implementation of add_assign (not provided in your example) would call into underneath.
seq += rhs;
In fact, adding it would only bring ambiguity, because then the compiler was being told to call Into<X>::into(rhs) on a type X which is never mentioned nor constrained anywhere. The only constraint would be Into<u64>, but multiple types fulfill it.
A complete example:
use std::ops::AddAssign;
struct Sequence;
impl<T: Into<u64>> AddAssign<T> for Sequence {
fn add_assign(&mut self, rhs: T) {
let value: u64 = rhs.into();
// use value
}
}
fn main() {
let mut x = Sequence;
x += 6_u32;
}
what is the syntax (if possible) to provide this type information to .into that the compiler needs?
Again, this is not needed. But that would be possible with the so-called fully qualified syntax.
See also:
Why can't Rust infer the resulting type of Iterator::sum?

Rust "doesn't have a size known at compile-time" error for iterators?

I'm refactoring the cartesian product code in Rust's itertools [1] as a way of learning Rust. The cartesian product is formed from an Iterator I and an IntoIterator J. The IntoIterator J is converted into an iterator multiple times and iterated over.
So far I have the code below, which is a minor modification of the code in the itertools source code. The biggest change is specifying a specific type (i8) instead of using generic types.
struct Product {
a: dyn Iterator<Item=i8>,
a_cur: Option<i8>,
b: dyn IntoIterator<Item=i8, IntoIter=dyn Iterator<Item=i8>>,
b_iter: dyn Iterator<Item=i8>
}
impl Iterator for Product {
type Item = (i8, i8);
fn next(&mut self) -> Option<Self::Item> {
let elt_b = match self.b_iter.next() {
None => {
self.b_iter = self.b.into_iter();
match self.b_iter.next() {
None => return None,
Some(x) => {
self.a_cur = self.a.next();
x
}
}
}
Some(x) => x
};
match self.a_cur {
None => None,
Some(ref a) => {
Some((a, elt_b))
}
}
}
}
fn cp(i: impl Iterator<Item=i8>, j: impl IntoIterator<Item=i8>) -> Product {
let p = Product{
a: i,
a_cur: i.next(),
b: j,
b_iter: j.into_iter()};
return p
}
fn main() {
for foo in cp(vec![1,4,7], vec![2,3,9]) {
println!("{:?}", foo);
}
}
Unfortunately the compiler is giving errors I have been unable to fix. I've attempted the fixes suggested by the compiler, but when I make them I get many more "doesn't have size known at compile time" errors.
I'm especially confused because the implementation in Rust's itertools library (link below) has a very similar structure and didn't require specifying lifetimes, borrowing, using Boxes, or the dyn keyword. I'd love to know what I changed that led to the Rust compiler suggesting using borrowing and/or Boxes.
error[E0277]: the size for values of type `(dyn Iterator<Item = i8> + 'static)` cannot be known at compilation time
--> src/main.rs:15:8
|
15 | a: dyn Iterator<Item=i8>,
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn Iterator<Item = i8> + 'static)`
= note: only the last field of a struct may have a dynamically sized type
= help: change the field's type to have a statically known size
help: borrowed types always have a statically known size
|
15 | a: &dyn Iterator<Item=i8>,
| ^
help: the `Box` type always has a statically known size and allocates its contents in the heap
|
15 | a: Box<dyn Iterator<Item=i8>>,
| ^^^^ ^
error[E0277]: the size for values of type `(dyn IntoIterator<Item = i8, IntoIter = (dyn Iterator<Item = i8> + 'static)> + 'static)` cannot be known at compilation time
--> src/main.rs:17:8
|
17 | b: dyn IntoIterator<Item=i8, IntoIter=dyn Iterator<Item=i8>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn IntoIterator<Item = i8, IntoIter = (dyn Iterator<Item = i8> + 'static)> + 'static)`
= note: only the last field of a struct may have a dynamically sized type
= help: change the field's type to have a statically known size
help: borrowed types always have a statically known size
|
17 | b: &dyn IntoIterator<Item=i8, IntoIter=dyn Iterator<Item=i8>>,
| ^
help: the `Box` type always has a statically known size and allocates its contents in the heap
|
17 | b: Box<dyn IntoIterator<Item=i8, IntoIter=dyn Iterator<Item=i8>>>,
| ^^^^ ^
error: aborting due to 2 previous errors
[1] Docs at https://nozaq.github.io/shogi-rs/itertools/trait.Itertools.html#method.cartesian_product and code at https://github.com/rust-itertools/itertools/blob/master/src/adaptors/mod.rs#L286 .
You didn't just change the item type, you also removed the generic iterator. In the itertools crate, there is:
pub struct Product<I, J>
where I: Iterator
{
a: I,
…
Meaning that a is an iterator whose exact type will be specified by the user (but still at compile time).
You have removed the generic I parameter and instead you have written:
pub struct Product
{
a: dyn Iterator<Item=i8>,
…
If that worked, it would mean that a is an iterator whose item type is u8 but whose exact type will be specified at runtime. Therefore at compile-time the compiler can't know the exact type of a nor how much space it should allocate to store a inside Product.
If you want your cartesian product to work for any iterator whose items are u8, you need to keep the generic parameter I with an extra constraint:
pub struct Product<I, J>
where I: Iterator<Item=u8>
{
a: I,
…
And a similar change will be required for J in impl Iterator.

Is it possible to check equality of closures in rust?

I am pretty new to rust, but for a practice project I am working on, I would like to implement a React useMemo like API, and I thought if the type of the closure is static, and the capture variables are stored somewhere, should I not be able to check equality?
Something like:
let cached = scope.use_memo(move || {
complicated_computation(captured_variable)
});
where use_memo is something like
pub fn use_memo<F: Fn() -> T + PartialEq + 'static, T: Clone + 'static>(&mut self, factory: F) -> &T
where in the code I can compare factory with a previously stored factory function and decide if factory needs to be rerun.
Obviously this doesn't work, since closures don't implement PartialEq, but I wonder if there are ways to achieve it.
No. Every closure has a separate type, even if they're identical, and you can't compare cross-type.
Looking at a minimal example:
fn main() {
let b = 2;
let a = if true {
|| println!("{}", b)
} else {
|| println!("{}", b)
};
}
we get a compiler error that helpfully explains that no two closures, even if identical, have the same type.
Compiling playground v0.0.1 (/playground)
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:6:9
|
3 | let a = if true {
| _____________-
4 | | || println!("{}", b)
| | -------------------- expected because of this
5 | | } else {
6 | | || println!("{}", b)
| | ^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
7 | | };
| |_____- `if` and `else` have incompatible types
|
= note: expected type `[closure#src/main.rs:4:9: 4:29 b:_]`
found closure `[closure#src/main.rs:6:9: 6:29 b:_]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
error: aborting due to previous error
You could build structs that contain the environment explicitly and compare those rather than using a closure, but I would suggest rethinking your problem and seeing if this is the best way to solve it.
I don't think it's possible: Rust closures are somewhat anonymous type so you can't implement traits on them or anything. And if you used more "explicit" closures where you build up the environment by hand and pass a simple function pointers:
fn use_memo<T: PartialEq>(&mut self, env: T, func: fn(T))
you could compare them:
fn main(){
let a: fn(u8) -> u8 = |a: u8| a;
let b: fn(u8) -> u8 = |a: u8| a % 2;
println!("{}", a == b) -> false
}
but then you'd have the issue that different callbacks would have different environments, therefore the types would not match and you still would not be able to compare them, probably.
I am also quite new in rust, but an idea might be to have a custom trait FactoryIdentifiable that defines a method get_identifier.
You could then use operator overloading and implement PartialEq for this trait and modify your closure's type signature to also require this trait.
pub fn use_memo<F: Fn() -> T + FactoryIdentifiable, T: Clone + 'static>(&mut self, factory: F) -> &T

Cannot infer type for type parameter `S` when using HashSet::from_iter

I am trying to solve an online challenge that involves comparing two sets. I followed this answer to convert my Vec<i32> output to HashSet
use std::collections::HashSet;
use std::iter::FromIterator;
struct Solution {}
impl Solution {
pub fn solve(nums: Vec<i32>, k: i32) -> Vec<i32> {
// todo, return dummy for now
return vec![1, 2];
}
}
fn main() {
assert_eq!(
HashSet::from_iter(Solution::solve(vec![1, 2, 3], 2)),
HashSet::from_iter(vec![1i32, 2i32])
)
}
For reasons I don't understand yet, the compilation fails:
error[E0282]: type annotations needed
--> src/main.rs:15:9
|
15 | HashSet::from_iter(Solution::solve(vec![1, 2, 3], 2)),
| ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `S` declared on the struct `HashSet`
It works fine for HashSet::from_iter(vec![1i32, 2i32])
I tried adding a type annotation like HashSet::from_iter::<Vec<i32>> with no avail. I also read the source implementation but still can't figure out what makes the compiler complain.
I can work around it by declaring it explicitly or construct the HashSet with a for loop and inserts, but I would like to understand what is going on here.
I'm using Rust 1.43.1.
I believe the answer from Kitsu is subtly incorrect since it suggests that Rust cannot infer the type of T because here may be an iterator implemented for a type P that collects a different type T (more on this at the end).
What's really happening
In fact, type inference for type S in HashSet<T, S> has nothing to do with the type of T. The issue is that there is no information in your program that allows the compiler to infer the type of S.
It is correct that adding a type parameter is sufficient to resolve the ambiguity:
HashSet::<i32>::from_iter(vec![1, 2, 3]);
This has nothing to do with the actual type you specify. Indeed, this works as well:
HashSet::<_>::from_iter(vec![1, 2, 3]);
The reason is that the definition of HashSet in the standard library includes a default type for S:
pub struct HashSet<T, S = RandomState> {
base: base::HashSet<T, S>,
}
By writing HashSet::<_>::from_iter(vec![1, 2, 3]); you're telling the compiler that it should use the default type for S, which is RandomState.
What about multiple implementations?
Kitsu's answer states that type inference fails for S because there might be multiple implementations of FromIterator. This is incorrect, but having multiple implementations can cause type inference to fail for T.
Consider this example:
fn iterator_demo() {
use std::collections::HashSet;
use std::hash::{BuildHasher, Hash};
use std::iter::FromIterator;
struct Empty;
impl<T, S> FromIterator<Empty> for HashSet<T, S>
where
T: Eq + Hash,
S: BuildHasher + Default,
{
fn from_iter<I>(iter: I) -> HashSet<T, S>
where
I: IntoIterator<Item = Empty>,
{
iter.into_iter().for_each(drop);
HashSet::default()
}
}
let x = HashSet::<_>::from_iter(vec![Empty, Empty]);
}
This causes type inference to fail; note that this is a failure to infer T, not S:
error[E0282]: type annotations needed for `HashSet<T>`
--> src/lib.rs:22:13
|
22 | let x = HashSet::<_>::from_iter(vec![Empty, Empty]);
| - ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
| |
| consider giving `x` the explicit type `HashSet<T>`, with the type parameters specified
Specifying the type resolves this ambiguity:
let x = HashSet::<String>::from_iter(vec![Empty, Empty]);
Credit to matt1992 on the Rust Discord for helping me to understand what's really happening here.
Let's look at the FromIterator::from_iter declaration, you've been using:
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = A>,
After specifying HashSet compiler can deduce that Self is HashSet<S> for some S. T for your particular case can be deduced as a Vec<i32>: IntoIterator<Item = i32> (for the second line that is resolved after you explicitly specified an integer type).
But still, S is not deduced because, in general, you may have an implementation that collects HashSet<u64> from IntoIterator<Item = u8>. So compiler cannot understand what are items of the collected type. Then if you swap the expressions of the assert_eq error source changes:
assert_eq!(
HashSet::from_iter(vec![1i32, 2i32]),
/*
|
15 | HashSet::from_iter(vec![1i32, 2i32]),
| ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `S` declared on the struct `HashSet`
*/
HashSet::from_iter(Solution::solve(vec![1, 2, 3], 2)),
)
The solution is fairly straightforward: you need to specify the item type of your HashSet:
assert_eq!(
HashSet::<i32>::from_iter(Solution::solve(vec![1, 2, 3], 2)),
HashSet::from_iter(vec![1i32, 2])
)

Trouble with Rust Lifetime in Generic function [duplicate]

This question already has answers here:
How to fix lifetime error when function returns a serde Deserialize type?
(2 answers)
Closed 3 years ago.
I have a simple function that I want to make generic, in rust. I am getting a lifetime error. I am still getting the hang of the lifetime side of rust.
The function simply converts 1 struct into another using serde's serialization.
Here is a a rust playground with the full simple scenario.
Code:
pub fn convert<'de: 'a, 'a, T>(from: &'a Left, print: bool) -> (T, &'a Left)
where
T: Deserialize<'de> + std::fmt::Debug {
let serialized = serde_json::to_string(&from);
let serialized = serialized.unwrap();
let deserialized: T;
{
let deserialized_raw = serde_json::from_str(&serialized);
deserialized = deserialized_raw.unwrap();
}
if print {
println!("-------------A-----------------------------------");
println!("serialized = {}", &serialized);
println!("--------------B----------------------------------");
println!("deserialized = {:?}", deserialized);
println!("--------------C----------------------------------");
};
(deserialized, from)
}
Error:
error[E0597]: `serialized` does not live long enough
--> src/main.rs:38:49
|
30 | pub fn convert<'de: 'a, 'a, T>(from: &'a Left, print: bool) -> (T, &'a Left)
| --- lifetime `'de` defined here
...
38 | let deserialized_raw = serde_json::from_str(&serialized);
| ---------------------^^^^^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `serialized` is borrowed for `'de`
...
49 | }
| - `serialized` dropped here while still borrowed
I tried this a few ways with and without lifetimes. I tried adding blocks to see if that changes things with no luck.
Any thoughts on what I am doing wrong?
Edited:
- Added the full compiler error output
To the compiler, lifetime parameters always represent lifetimes that live strictly longer than the function call. However, here you're trying to use a local variable and claim it has lifetime 'de, which is impossible because it's a local variable, thus it has a lifetime shorter than the function call.
In order to mix lifetime parameters in traits with local variables, we must use higher-rank trait bounds. We want T to implement Deserialize<'de> for every lifetime 'de (not just one specific lifetime chosen by the caller). This is written like this (note that we can now elide the 'a lifetime):
pub fn convert<T>(from: &Left, print: bool) -> (T, &Left)
where
T: for<'de> Deserialize<'de> + std::fmt::Debug
{
// no changes here
}

Resources