Как я могу определить универсальную функцию, которая может возвращать данный целочисленный тип? - PullRequest
0 голосов
/ 13 октября 2019

Я бы хотел определить функцию, которая может возвращать число, тип которого указан при вызове функции. Функция принимает буфер (Vec<u8>) и возвращает числовое значение, например,

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

. Буфер содержит строку ASCII, которая представляет число, например b"827", где каждый байт является кодом ASCIIцифра.

Это мой нерабочий код:

  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
  } 

Я получаю несоответствующие ошибки типа как для сложения, так и для умножения (expected type T, found u32). Поэтому я думаю, что моя проблема в том, как сказать системе типов, что T можно выразить в виде литерала 10 или в виде результата (byte - b'0')?

1 Ответ

2 голосов
/ 13 октября 2019

Добро пожаловать в необходимость указывать каждую отдельную операцию, которую вы используете в качестве универсальной. Это боль, но она того стоит.

У вас есть две проблемы:

  1. result *= 10; без соответствующего определения From<_>. Это связано с тем, что когда вы указываете «10», компилятор не может узнать, что означает «10» как T - он знает примитивные типы и любое преобразование, которое вы определили с помощью реализации From<_> traits
  2. Вы смешиваете две операции - приведение вектора символов к целому числу и вашу операцию.

Для этого нам нужно сделать два предположения:

  • Нам потребуется From<u32>, чтобы мы могли ограничить наши числа до u32

  • Мы также уточним вашу логику и преобразуем каждый u8 в char такмы можем использовать to_digit() для преобразования этого в u32, прежде чем использовать From<u32> для получения 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можете убедить себя в его поведении на игровой площадке

Умножение разрешается путем принудительного приведения константы в значение u8, что позволяет ей воспользоваться нашим требованиемFrom<u8> для T и позволяет ржавому компилятору знать, что мы не делаем глупостей.

ФайКонечное изменение - установить для result значение по умолчанию 0.

Дайте мне знать, если это имеет смысл для вас (или если нет), и я буду рад уточнить, еслиесть проблема: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...