Previous error with Infer type

i cant resolve previous error, and i don't know what wrong with it.

use std::any::type_name;

pub fn scaleValue<T: PartialEq +
                     std::ops::Shl<Output = i32> +
                     std::ops::Shr<Output = i32> +
                     std::ops::Shl<Output = i16> +
                     std::ops::Shr<Output = i16> >
    (value: &'static T, scalefactor: i32) -> T {
    match type_name() {
        "i32"=> if scalefactor > 0 { return *value << scalefactor } else { return *value >> (-scalefactor); },
        "i16" => if scalefactor > 0 { return *value << scalefactor } else { return *value >> (-scalefactor); },
        _ => panic!("invalid variable type")
    }
}

fn main() {
    let x: i32 = 2;
    let y: i16 = 2;

    let a = scaleValue(&x, 4);
    let b = scaleValue(&y, 4);

}

here error code

error[E0282]: type annotations needed
 --> src/main.rs:5:26
  |
5 | pub fn testScaleValue<T: std::ops::Shl<Output = i32> +
  |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type

error: aborting due to previous error

For more information about this error, try `rustc --explain E0282`.

Well... there’s so much more going on here than just the error message you’ve presented (actually, the error you show isn’t even one that I’m getting, AFAICT):

type_name is for debugging purposes, so please don’t match on its results

This is intended for diagnostic use. The exact contents and format of the string returned are not specified, other than being a best-effort description of the type.

Furthermore, it is called by providing an explicit type argument, like type_name::<T>(). If you don’t provide the argument, is will give you an error because the compiler can’t infer what it is supposed to do in any other way.

Shl and Shr are such that T: Shl<Output = i32> is short for T: Shl<T, Output = i32>, and in general A: Shl<B, Output = C> means that you can use a: A and b: B in an expression a << b whose result will be of type C.

I don’t really know what the purpose of all the details of your function implementations is: there’s quite a few trait bounds bounds, where you check for Shl and Shr implementations involving i32 and i16 and also PartialEq, even though there’s no i16 or == to be seen; and you also have this weird matching-on-the-type-of-T logic going on. Furthermore, your return *value << scalefactor combines a T with a i32, expecting a T result (judging by the signature of scaleValue), so the bound you actually need will be something like T: Shl<i32, Output = T>, which is currently missing.

Also you require &'static T. I would advise against using &'static for anything but (very occasionally) the type &'static str of string literals, in particular as long as you’re not sure about what the 'static it does. Furthermore, going from &T to T by dereferencing like in *value doesn’t even work for non-Copy types. For Copy types then, it is more ergonomic to just take the type by value anyways, in which case then the copying inside of scale_value isn’t even needed anymore.

So after all this said, with some adjustments, in particular ignoring all the i16s, your function can be written as:

use std::ops::{Shl, Shr};

pub fn scale_value<T>(value: T, scalefactor: i32) -> T
where
    T: Shl<i32, Output = T> + Shr<i32, Output = T>,
{
    if scalefactor > 0 {
        value << scalefactor
    } else {
        value >> -scalefactor
    }
}

fn main() {
    let x: i32 = 2;
    let y: i16 = 2;

    let a = scale_value(x, 4);
    let b = scale_value(y, 4);

    // print the values
    dbg!(a, b);
}
3 Likes

thanks @steffahn your reply be solution to me, here the original c code. i translated to rust but getting stuck.

inline FIXP_DBL scaleValue(const FIXP_DBL value, /*!< Value */
                            INT scalefactor       /*!< Scalefactor */
 ) {
   if (scalefactor > 0)
     return (value << scalefactor);
   else
     return (value >> (-scalefactor));
}

 inline FIXP_SGL scaleValue(const FIXP_SGL value, /*!< Value */
                            INT scalefactor       /*!< Scalefactor */
 ) {
   if (scalefactor > 0)
     return (value << scalefactor);
   else
     return (value >> (-scalefactor));
 }