# Expected i32, found associated type

I’m not sure it is a good solution. Besides, it doesn’t work.

``````  Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/main.rs:120:30
|
|                                             ^^^^^^ expected i32, found associated type
|
= note: expected type `i32`
found type `<impl Stackful as Stackful>::T`
``````

Do I need GAT for this? How can this be solved in a generic way?
I’m collect arithmetic operations and calculate the result. I need this for example for i32 and f32. I don’t want duplicated code and learn more about generics. I don’t have a problem with turbofish, if this comes necessary, go for it.

For any help I’m thankful.

Make a trait for arithmetic operators and implement it for both u32 and f32
You can then use that trait as an interface to do the math in Calculator.
No GATs required.

1 Like

Could you help me further? I’m not sure how to go from here

``````use std::collections::BTreeMap;

#[derive(Debug)]
pub enum Operation {
SUBTRACTION,
DIVISION,
MULTIPLICATION,
NONE,
}

pub struct UnitHelperI32 {
stack: BTreeMap<u64, (i32, Operation)>,
count: u64,
}

pub struct UnitHelperF32 {
stack: BTreeMap<u64, (f32, Operation)>,
count: u64,
}

trait Arithmetic<T> {
fn new() -> Self;
fn get_stack(&mut self) -> &BTreeMap<u64, (T, Operation)>;
fn erase_operation(&mut self, id: u64);
fn add<V>(&mut self, operand: V) -> u64 where V: Into<T> + Copy;
fn sub<V>(&mut self, operand: V) -> u64 where V: Into<T> + Copy;
fn div<V>(&mut self, operand: V) -> u64 where V: Into<T> + Copy;
fn mul<V>(&mut self, operand: V) -> u64 where V: Into<T> + Copy;
}

impl<T> Arithmetic<T> for UnitHelperI32{
fn new() -> Self {
Self {stack: BTreeMap::new(), count: 0}
}
fn get_stack(&mut self) -> &BTreeMap<u64, (i32, Operation)> {
&self.stack
}
fn erase_operation(&mut self, id: u64) {
self.stack.insert(id, (0, Operation::NONE));
}
fn add<V>(&mut self, operand: V) -> u64 where V: Into<i32> + Copy {
let count = self.count;
self.count += 1;
count
}
fn sub<V>(&mut self, operand: V) -> u64 where V: Into<i32> + Copy {
self.stack.insert(self.count, (operand.into(), Operation::SUBTRACTION));
let count = self.count;
self.count += 1;
count
}
fn div<V>(&mut self, operand: V) -> u64 where V: Into<i32> + Copy {
self.stack.insert(self.count, (operand.into(), Operation::DIVISION));
let count = self.count;
self.count += 1;
count
}
fn mul<V>(&mut self, operand: V) -> u64 where V: Into<i32> + Copy {
self.stack.insert(self.count, (operand.into(), Operation::MULTIPLICATION));
let count = self.count;
self.count += 1;
count
}
}

impl<T> Arithmetic<T> for UnitHelperF32{
fn new() -> Self {
Self {stack: BTreeMap::new(), count: 0}
}
fn get_stack(&mut self) -> &BTreeMap<u64, (f32, Operation)> {
&self.stack
}
fn erase_operation(&mut self, id: u64) {
self.stack.insert(id, (0.0, Operation::NONE));
}
fn add<V>(&mut self, operand: V) -> u64 where V: Into<f32> + Copy {
let count = self.count;
self.count += 1;
count
}
fn sub<V>(&mut self, operand: V) -> u64 where V: Into<f32> + Copy {
self.stack.insert(self.count, (operand.into(), Operation::SUBTRACTION));
let count = self.count;
self.count += 1;
count
}
fn div<V>(&mut self, operand: V) -> u64 where V: Into<f32> + Copy {
self.stack.insert(self.count, (operand.into(), Operation::DIVISION));
let count = self.count;
self.count += 1;
count
}
fn mul<V>(&mut self, operand: V) -> u64 where V: Into<f32> + Copy {
self.stack.insert(self.count, (operand.into(), Operation::MULTIPLICATION));
let count = self.count;
self.count += 1;
count
}
}

struct Calculator {}

impl Calculator {
pub fn result(&mut self, helper: &mut impl Arithmetic, initial: i32) -> i32 {
let mut v = initial;
let mut overflow = false;
for (_id, (value, operation)) in helper.get_stack() {
match operation {
(value, false) => v = value,
(v, true) => { overflow = true; }
}
}
Operation::SUBTRACTION => {
match v.overflowing_sub(*value) {
(value, false) => v = value,
(_, true) => { overflow = true; }
}
}
Operation::DIVISION => {
match v.overflowing_div(*value) {
(value, false) => v = value,
(_, true) => { overflow = true; }
}
}
Operation::MULTIPLICATION => {
match v.overflowing_mul(*value) {
(value, false) => v = value,
(_, true) => { overflow = true; }
}
}
Operation::NONE => {}
}
if overflow {
break;
}
}
v
}
}

fn main(){
let mut calculator = Calculator {};
let mut helper = UnitHelperF32::new();
let id = helper.mul(2000.0);
helper.sub(10.0);
helper.erase_operation(id);
println!(": {:?}",helper.get_stack());
let result = calculator.result(&mut helper,1000000000);
println!("result: {:?}", result);
}
``````

Would something like this work

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a2f4fc5826716e370f6c86aee446eda0

The `Arithmetic` trait handles the operations

On an unrelated note, you can use `Vec` for an efficient stack instead of a `BTreeMap`, it would work out better. Like so

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=10516191390149478b21275fb4c4cdce

2 Likes

Nice and clean. I like it very much. Thank you. I will have a thorough look at it tomorrow.

1 Like

Okay, a related issue. Is there a way to make this compile?

`````` --> src/main.rs:9:16
|
9 |     if value > 0.0 {
|                ^ expected type parameter, found integer
|
= note: expected type `T`
found type `{float}`

error: aborting due to previous error

``````
``````trait Arithmetic: Sized {}
impl Arithmetic for f64 {}

fn main() {}

fn f1<T>(value: T) where T: Arithmetic + Copy + std::cmp::PartialOrd + std::fmt::Debug + std::fmt::Display {
let mut s=String::new();
if value > 0.0 {
s.push_str(&format!("..{}..",value));
}
}

``````

``````trait Arithmetic: Sized {}
impl Arithmetic for f64 {}

fn main() {}

fn f1<T: From<float>(value: T) where T: Arithmetic + Copy + std::cmp::PartialOrd + std::fmt::Debug +
std::fmt::Display {
let mut s=String::new();
if value > T::from(0.0) {
s.push_str(&format!("..{}..",value));
}
}``````
1 Like

The problem is, `T` is `PartialOrd<T>` but the actual type `T` is unknown here so you can’t compare `T` with `{float}`(non-integer number literal). You can constraint `T: PartialOrd<f64>` in the signature to let compiler infer the `0.0` written here is actually `f64`

1 Like

thank you, but I get an error on playground (if I fix the missing >)

``````cannot find type `float` in this scope --> src/main.rs:6:15
``````

If I add the constraint `T: PartialOrd<f64>` I loose the generic formulation of the function. Okay, saying 0.0 or 0 then it has already stopped being generic over T. But there is `is_negative()` for numbers.
So what if I add a new impl for the trait Arithmetic `impl Arithmetic for i64 {}`. Can I still formulate the function f1 generic?