Understanding type inference in Rust [duplicate] - rust

This code works:
fn main() {
let a: i32 = (1i32..10).sum();
let b = a.pow(2);
}
If I remove the i32 type from a, then I get this error:
rustc 1.13.0 (2c6933acc 2016-11-07)
error: the type of this value must be known in this context
--> <anon>:3:13
|
5 | let b = a.pow(2);
| ^^^^^^^^
Run the example
I would have expected that Rust turns (1i32..10) into an i32 iterator and then sum() knows to return an i32. What am I missing?

The way sum is defined, the return value is open-ended; more than one type can implement the trait Sum<i32>. Here's an example where different types for a are used, both of which compile:
#[derive(Clone, Copy)]
struct Summer {
s: isize,
}
impl Summer {
fn pow(&self, p: isize) {
println!("pow({})", p);
}
}
impl std::iter::Sum<i32> for Summer {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = i32>,
{
let mut result = 0isize;
for v in iter {
result += v as isize;
}
Summer { s: result }
}
}
fn main() {
let a1: i32 = (1i32..10).sum();
let a2: Summer = (1i32..10).sum();
let b1 = a1.pow(2);
let b2 = a2.pow(2);
}
Playground
Since both result types are possible, the type cannot be inferred and must be explicitly specified, either by a turbofish (sum::<X>()) or as the result of the expression (let x: X = ...sum();).

and then sum() knows to return an i32
This is the key missing point. While the "input" type is already known (it has to be something that implements Iterator in order for sum to even be available), the "output" type is very flexible.
Check out Iterator::sum:
fn sum<S>(self) -> S
where
S: Sum<Self::Item>,
It returns a generic type S which has to implement Sum. S does not have to match Self::Item. Therefore, the compiler requires you to specify what
type to sum into.
Why is this useful? Check out these two sample implementations from the standard library:
impl Sum<i8> for i8
impl<'a> Sum<&'a i8> for i8
That's right! You can sum up an iterator of u8 or an iterator of &u8! If we didn't have this, then this code wouldn't work:
fn main() {
let a: i32 = (0..5).sum();
let b: i32 = [0, 1, 2, 3, 4].iter().sum();
assert_eq!(a, b);
}
As bluss points out, we could accomplish this by having an associated type which would tie u8 -> u8 and &'a u8 -> u8.
If we only had an associated type though, then the target sum type would always be fixed, and we'd lose flexibility. See When is it appropriate to use an associated type versus a generic type? for more details.
As an example, we can also implement Sum<u8> for our own types. Here, we sum up u8s, but increase the size of the type we are summing, as it's likely the sum would exceed a u8. This implementation is in addition to the existing implementations from the standard library:
#[derive(Debug, Copy, Clone)]
struct Points(i32);
impl std::iter::Sum<u8> for Points {
fn sum<I>(iter: I) -> Points
where
I: Iterator<Item = u8>,
{
let mut pts = Points(0);
for v in iter {
pts.0 += v as i32;
}
pts
}
}
fn main() {
let total: Points = (0u8..42u8).sum();
println!("{:?}", total);
}

Related

Why Rust can't coerce mutable reference to immutable reference in a type constructor?

It is possible to coerce &mut T into &T but it doesn't work if the type mismatch happens within a type constructor.
playground
use ndarray::*; // 0.13.0
fn print(a: &ArrayView1<i32>) {
println!("{:?}", a);
}
pub fn test() {
let mut x = array![1i32, 2, 3];
print(&x.view_mut());
}
For the above code I get following error:
|
9 | print(&x.view_mut());
| ^^^^^^^^^^^^^ types differ in mutability
|
= note: expected reference `&ndarray::ArrayBase<ndarray::ViewRepr<&i32>, ndarray::dimension::dim::Dim<[usize; 1]>>`
found reference `&ndarray::ArrayBase<ndarray::ViewRepr<&mut i32>, ndarray::dimension::dim::Dim<[usize; 1]>>`
It is safe to coerce &mut i32 to &i32 so why it is not applied in this situation? Could you provide some examples on how could it possibly backfire?
In general, it's not safe to coerce Type<&mut T> into Type<&T>.
For example, consider this wrapper type, which is implemented without any unsafe code and is therefore sound:
#[derive(Copy, Clone)]
struct Wrapper<T>(T);
impl<T: Deref> Deref for Wrapper<T> {
type Target = T::Target;
fn deref(&self) -> &T::Target { &self.0 }
}
impl<T: DerefMut> DerefMut for Wrapper<T> {
fn deref_mut(&mut self) -> &mut T::Target { &mut self.0 }
}
This type has the property that &Wrapper<&T> automatically dereferences to &T, and &mut Wrapper<&mut T> automatically dereferences to &mut T. In addition, Wrapper<T> is copyable if T is.
Assume that there exists a function that can take a &Wrapper<&mut T> and coerce it into a &Wrapper<&T>:
fn downgrade_wrapper_ref<'a, 'b, T: ?Sized>(w: &'a Wrapper<&'b mut T>) -> &'a Wrapper<&'b T> {
unsafe {
// the internals of this function is not important
}
}
By using this function, it is possible to get a mutable and immutable reference to the same value at the same time:
fn main() {
let mut value: i32 = 0;
let mut x: Wrapper<&mut i32> = Wrapper(&mut value);
let x_ref: &Wrapper<&mut i32> = &x;
let y_ref: &Wrapper<&i32> = downgrade_wrapper_ref(x_ref);
let y: Wrapper<&i32> = *y_ref;
let a: &mut i32 = &mut *x;
let b: &i32 = &*y;
// these two lines will print the same addresses
// meaning the references point to the same value!
println!("a = {:p}", a as &mut i32); // "a = 0x7ffe56ca6ba4"
println!("b = {:p}", b as &i32); // "b = 0x7ffe56ca6ba4"
}
Full playground example
This is not allowed in Rust, leads to undefined behavior and means that the function downgrade_wrapper_ref is unsound in this case. There may be other specific cases where you, as the programmer, can guarantee that this won't happen, but it still requires you to implement it specifically for those case, using unsafe code, to ensure that you take the responsibility of making those guarantees.
Consider this check for an empty string that relies on content staying unchanged for the runtime of the is_empty function (for illustration purposes only, don't use this in production code):
struct Container<T> {
content: T
}
impl<T> Container<T> {
fn new(content: T) -> Self
{
Self { content }
}
}
impl<'a> Container<&'a String> {
fn is_empty(&self, s: &str) -> bool
{
let str = format!("{}{}", self.content, s);
&str == s
}
}
fn main() {
let mut foo : String = "foo".to_owned();
let container : Container<&mut String> = Container::new(&mut foo);
std::thread::spawn(|| {
container.content.replace_range(1..2, "");
});
println!("an empty str is actually empty: {}", container.is_empty(""))
}
(Playground)
This code does not compile since &mut String does not coerce into &String. If it did, however, it would be possible that the newly created thread changed the content after the format! call but before the equal comparison in the is_empty function, thereby invalidating the assumption that the container's content was immutable, which is required for the empty check.
It seems type coercions don't apply to array elements when array is the function parameter type.
playground

Error while calculating Getting average of chunks [duplicate]

This code works:
fn main() {
let a: i32 = (1i32..10).sum();
let b = a.pow(2);
}
If I remove the i32 type from a, then I get this error:
rustc 1.13.0 (2c6933acc 2016-11-07)
error: the type of this value must be known in this context
--> <anon>:3:13
|
5 | let b = a.pow(2);
| ^^^^^^^^
Run the example
I would have expected that Rust turns (1i32..10) into an i32 iterator and then sum() knows to return an i32. What am I missing?
The way sum is defined, the return value is open-ended; more than one type can implement the trait Sum<i32>. Here's an example where different types for a are used, both of which compile:
#[derive(Clone, Copy)]
struct Summer {
s: isize,
}
impl Summer {
fn pow(&self, p: isize) {
println!("pow({})", p);
}
}
impl std::iter::Sum<i32> for Summer {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = i32>,
{
let mut result = 0isize;
for v in iter {
result += v as isize;
}
Summer { s: result }
}
}
fn main() {
let a1: i32 = (1i32..10).sum();
let a2: Summer = (1i32..10).sum();
let b1 = a1.pow(2);
let b2 = a2.pow(2);
}
Playground
Since both result types are possible, the type cannot be inferred and must be explicitly specified, either by a turbofish (sum::<X>()) or as the result of the expression (let x: X = ...sum();).
and then sum() knows to return an i32
This is the key missing point. While the "input" type is already known (it has to be something that implements Iterator in order for sum to even be available), the "output" type is very flexible.
Check out Iterator::sum:
fn sum<S>(self) -> S
where
S: Sum<Self::Item>,
It returns a generic type S which has to implement Sum. S does not have to match Self::Item. Therefore, the compiler requires you to specify what
type to sum into.
Why is this useful? Check out these two sample implementations from the standard library:
impl Sum<i8> for i8
impl<'a> Sum<&'a i8> for i8
That's right! You can sum up an iterator of u8 or an iterator of &u8! If we didn't have this, then this code wouldn't work:
fn main() {
let a: i32 = (0..5).sum();
let b: i32 = [0, 1, 2, 3, 4].iter().sum();
assert_eq!(a, b);
}
As bluss points out, we could accomplish this by having an associated type which would tie u8 -> u8 and &'a u8 -> u8.
If we only had an associated type though, then the target sum type would always be fixed, and we'd lose flexibility. See When is it appropriate to use an associated type versus a generic type? for more details.
As an example, we can also implement Sum<u8> for our own types. Here, we sum up u8s, but increase the size of the type we are summing, as it's likely the sum would exceed a u8. This implementation is in addition to the existing implementations from the standard library:
#[derive(Debug, Copy, Clone)]
struct Points(i32);
impl std::iter::Sum<u8> for Points {
fn sum<I>(iter: I) -> Points
where
I: Iterator<Item = u8>,
{
let mut pts = Points(0);
for v in iter {
pts.0 += v as i32;
}
pts
}
}
fn main() {
let total: Points = (0u8..42u8).sum();
println!("{:?}", total);
}

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.

Generic Type Mismatch using Trait in Rust

I am doing a matrix addition using traits. I am stuck by the generic type mismatch. My code is as following:
use std::{ops, fmt};
#[derive(PartialEq, Debug)]
pub struct Matrix<T> {
data: Vec<T>,
row: usize,
col: usize,
}
impl<T: Copy> Matrix<T> {
/// Creates a new matrix of `row` rows and `col` columns, and initializes
/// the matrix with the elements in `values` in row-major order.
pub fn new(row: usize, col: usize, values: &[T]) -> Matrix<T> {
Matrix {
data: values.to_vec(), // make copy and convert &[T] to vector type
row: row,
col: col,
}
}
}
impl<T: ops::Add<Output = T> + Copy> ops::Add for Matrix<T> {
type Output = Self;
/// Returns the sum of `self` and `rhs`. If `self.row != rhs.row || self.col != rhs.col`, panic.
fn add(self, rhs: Self) -> Self::Output {
assert!(self.col == rhs.col);
assert!(self.row == rhs.row);
let mut newdata = Vec::new(); // make a new vector to store result
let mut sum: i32; // temp variable to record each addition
for num1 in self.data.iter() {
for num2 in rhs.data.iter() {
sum = *num1 + *num2;
newdata.push(sum)
}
}
Matrix {
data: newdata, // finally, return addition result using new_data
row: self.row,
col: self.col,
}
}
}
fn main() {
let x = Matrix::new(2, 3, &[-6, -5, 0, 1, 2, 3]);
let y = Matrix::new(2, 3, &[0, 1, 0, 0, 0, 0]);
// z = x + y;
}
Compiling the program, I got two errors about type mismatch:
error[E0308]: mismatched types
--> src/main.rs:36:23
|
36 | sum = *num1 + *num2;
| ^^^^^^^^^^^^^ expected i32, found type parameter
|
= note: expected type `i32`
= note: found type `T`
error[E0308]: mismatched types
--> src/main.rs:41:9
|
41 | Matrix {
| ^ expected type parameter, found i32
|
= note: expected type `Matrix<T>`
= note: found type `Matrix<i32>`
My thoughts:
num1 would deref the vector and get a integer type, that's why I use a sum to record the result.
I am trying to return a Matrix type value at the end of the function.
What is going wrong?
This is the entire knowledge of your types that the code can rely on inside of the method:
impl<T: ops::Add<Output = T> + Copy> ops::Add for Matrix<T> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
// ...
}
}
Based on that, how would it be possible to make this assumption?
num1 would deref the vector and get a integer type
There is no way to know what concrete type T will be!
Beyond that, even if it were some integer type, how would it be possible to assume that summing into an i32 is acceptable? What if T were a i64?
The solution is to remove any assumptions and let the compiler do its job. Remove the type annotation from sum and the code compiles. I find it good practice to always allow the compiler to infer my types when possible.
See also:
Requiring implementation of Mul in generic function
"Expected type parameter" error in the constructor of a generic struct

How can I use `index_mut` to get a mutable reference?

Even when I implement IndexMut for my struct, I cannot get a mutable reference to an element of structure inner vector.
use std::ops::{Index, IndexMut};
struct Test<T> {
data: Vec<T>,
}
impl<T> Index<usize> for Test<T> {
type Output = T;
fn index<'a>(&'a self, idx: usize) -> &'a T {
return &self.data[idx];
}
}
impl<T> IndexMut<usize> for Test<T> {
fn index_mut<'a>(&'a mut self, idx: usize) -> &'a mut T {
// even here I cannot get mutable reference to self.data[idx]
return self.data.index_mut(idx);
}
}
fn main() {
let mut a: Test<i32> = Test { data: Vec::new() };
a.data.push(1);
a.data.push(2);
a.data.push(3);
let mut b = a[1];
b = 10;
// will print `[1, 2, 3]` instead of [1, 10, 3]
println!("[{}, {}, {}]", a.data[0], a.data[1], a.data[2]);
}
How can I use index_mut to get a mutable reference? Is it possible?
You're almost there. Change this:
let mut b = a[1];
b = 10;
to this:
let b = &mut a[1];
*b = 10;
Indexing syntax returns the value itself, not a reference to it. Your code extracts one i32 from your vector and modifies the variable - naturally, it does not affect the vector itself. In order to obtain a reference through the index, you need to write it explicitly.
This is fairly natural: when you use indexing to access elements of a slice or an array, you get the values of the elements, not references to them, and in order to get a reference you need to write it explicitly.

Resources