Создание универсальной функции, связанной с целочисленными типами - PullRequest
1 голос
/ 09 ноября 2019

В моей попытке изучить ржавчину я начинаю с некоторых базовых упражнений. Я написал простую функцию, которая, как я надеюсь, является идиоматической ржавчиной для подсчета количества установленных бит в целом числе.

fn bit_count(x: u32) -> u32 {
    (0..32).into_iter().map(|i| (x >> i) & 1).sum()
}

fn main() {
    println!("{} has {} set bits.", 5, bit_count(5));
}

Теперь я хочу сделать функцию универсальной, чтобы я мог передавать любой целочисленный тип:i32, u32, i64, u64 ... и т. Д.

Я довольно хорошо знаком с tmp в c ++, но моя попытка с дженериками ржавчины провалилась, поэтому у меня есть следующее:

extern crate num;

fn bit_count<T>(x: T) -> T
where
    T: num::Integer + std::ops::BitAnd + std::ops::Shr + num::NumCast,
    std::ops::Range<T>: std::iter::IntoIterator,
{
    (T::zero()..num::NumCast::from(32).unwrap())
        .into_iter()
        .map(|i| (x >> num::NumCast::from(i)) & T::one())
        .sum()
}

fn main() {
    println!("{} has {} set bits.", 5, bit_count(5));
}

Я увидел объявленный num ящик, и он показался мне подходящим. Я ожидал, что у меня будет T: num::Integer, и все будет готово, однако я чувствую, что здесь скручиваю кроличью нору, и я не могу получить правильную комбинацию границ.

Любые предложения были бы хорошими! и любые советы, которые сделают мой код более идиоматическим, также будут полезны, спасибо.

1 Ответ

0 голосов
/ 09 ноября 2019

Получил в конце. Оказывается, мне нужно было использовать черту num::PrimInt в качестве моей границы, поскольку она включает все побитовые операции и приведение типов. num::Integer менее ограничен и моделирует целое число в чистом математическом смысле, так что нет побитовых операций.

Окончательный код, который я имею, выглядит так:

extern crate num;

fn bit_count<T>(x: T) -> T
where
    T: num::PrimInt + std::iter::Sum,
{    
    let n_bits = std::mem::size_of::<T>() * 8;
    (0..n_bits).into_iter().map(|i| (x >> i) & T::one()).sum()

}

fn main() {
    println!("{} has {} set bits.", 5, bit_count(5u32));
    println!("{} has {} set bits.", 5, bit_count(5i32));
    println!("{} has {} set bits.", 5, bit_count(5i64));
}

Было бы неплохочтобы не нуждаться в этом T::one(), но, кажется, нет никакого способа обойти это. Кроме того, черта std::iter::Sum была необходима в моих границах, чтобы обеспечить функциональный рабочий процесс.

Ящик num на самом деле имеет функцию для подсчета количества установленных битов num::PrimInt::count_ones.

...