Expected type parameter `T`, found integer

I want to implement Pagination object, but my code do not compliles because of trait:

error[E0308]: mismatched types
  --> src/lib.rs:18:31
   |
9  | impl<T: Integer> Pagination<T> {
   |      - this type parameter
...
18 |         let total_pages = 0..=self.items_count / self.per_page;
   |                           ----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                           |   |
   |                           |   expected integer, found type parameter `T`
   |                           arguments to this function are incorrect
   |
   = note:        expected type `{integer}`
           found type parameter `T`
note: associated function defined here

error[E0308]: mismatched types
  --> src/lib.rs:20:40
   |
9  | impl<T: Integer> Pagination<T> {
   |      - this type parameter
...
20 |             if index > self.per_page * page {
   |                                        ^^^^ expected type parameter `T`, found integer
   |
   = note: expected type parameter `T`
                        found type `{integer}`

this is my code:

use num::Integer;
use std::io::{Error, ErrorKind};

struct Pagination<T: Integer> {
    items_count: T,
    per_page: T,
}

impl<T: Integer> Pagination<T> {
    pub fn new(items_count: T, per_page: T) -> Self {
        Self {
            items_count,
            per_page,
        }
    }
    
    pub fn get_page_number(&mut self, index: T) -> Result<T, Error> {
        let total_pages = 0..=self.items_count / self.per_page;
        for page in total_pages.rev() {
            if index > self.per_page * page {
                return Ok(page);
            }
        }
        
        Err(Error::new(ErrorKind::Other, ""))
    }
}

This is sandbox

Could somebody explain what I did wrong ? I just want to allow Pagination to be any integer (like u32, u16, u128 etc). Probably I should use another trait ?

No amounts of traits will allow that as-is; a trait doesn't describe what a type's identity is; it only describes how it behaves. I.e., you simply can't create a trait that describes "this might be either u8 or i8 or u16 or i16" etc.; you can only create and use a trait that describes that "this type can be multiplied by itself and the result is itself", etc.

Now there's a really easy solution to this problem: write the code in a way that it doesn't care about the exact type! That is exactly what generics and traits are for, incidentally. Program against interfaces, not implementations.

One way to do this would be to specify that the start of the range is the zero value, and that it's interconvertible with usize, which is what you should be using for counts and sizes anyway:

impl<T: Copy + Integer + NumCast> Pagination<T> {
    pub fn get_page_number(&mut self, index: T) -> Result<T, Error> {
        let total_pages = (self.items_count / self.per_page).to_usize().ok_or_else(|| {
            Error::new(ErrorKind::Other, "can't count using this type")
        })?;
        let per_page = self.per_page.to_usize().ok_or_else(|| {
            Error::new(ErrorKind::Other, "can't count using this type")
        })?;
        let index = index.to_usize().ok_or_else(|| {
            Error::new(ErrorKind::Other, "can't count using this type")
        })?;
        
        for page in (0..=total_pages).rev() {
            if index > per_page * page {
                return T::from(page).ok_or_else(|| {
                    Error::new(ErrorKind::Other, "can't count using this type")
                });
            }
        }
        
        Err(Error::new(ErrorKind::Other, ""))
    }
}

By the way, you really-really don't want to bound the type parameter in the struct declaration or in impl blocks that don't need it. It's an unnecessary restriction that does nothing but make your interface annoying to use.

1 Like

Thank you for detailed explanation !

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.