简体   繁体   中英

How can I define a generic function that can return a given integer type?

I'd like to define a function that can return a number whose type is specified when the function is called. The function takes a buffer ( Vec<u8> ) and returns numeric value, eg

let byte = buf_to_num<u8>(&buf);
let integer = buf_to_num<u32>(&buf);

The buffer contains an ASCII string that represents a number, eg b"827" , where each byte is the ASCII code of a digit.

This is my non-working code:

  extern crate num;
  use num::Integer;
  use std::ops::{MulAssign, AddAssign};

  fn buf_to_num<T: Integer + MulAssign + AddAssign>(buf: &Vec::<u8>) -> T {
    let mut result : T;
    for byte in buf {
      result *= 10;
      result += (byte - b'0');
    }
    result
  } 

I get mismatched type errors for both the addition and the multiplication lines ( expected type T, found u32 ). So I guess my problem is how to tell the type system that T can be expressed in terms of a literal 10 or in terms of the result of (byte - b'0') ?

Welcome to the joys of having to specify every single operation you're using as a generic. It's a pain, but it is worth.

You have two problems:

  1. result *= 10; without a corresponding From<_> definition. This is because, when you specify "10", there is no way for the compiler to know what "10" as a T means - it knows primitive types, and any conversion you defined by implementing From<_> traits
  2. You're mixing up two operations - coercion from a vector of characters to an integer, and your operation.

We need to make two assumptions for this:

  • We will require From<u32> so we can cap our numbers to u32

  • We will also clarify your logic and convert each u8 to char so we can use to_digit() to convert that to u32 , before making use of From<u32> to get a T .

     use std::ops::{MulAssign, AddAssign}; fn parse_to_i<T: From<u32> + MulAssign + AddAssign>(buf: &[u8]) -> T { let mut buffer:T = (0 as u32).into(); for o in buf { buffer *= 10.into(); buffer += (*o as char).to_digit(10).unwrap_or(0).into(); } buffer }

You can convince yourself of its behavior on the playground

The multiplication is resolved by force-casting the constant as u8 , which makes it benefit from our requirement of From<u8> for T and allows the rust compiler to know we're not doing silly stuff.

The final change is to set result to have a default value of 0.

Let me know if this makes sense to you (or if it doesn't), and I'll be glad to elaborate further if there is a problem:-)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM