Конвертировать в f32 в реализации черты - PullRequest
0 голосов
/ 17 октября 2019

Чтобы изучить ржавчину, я попытался реализовать общий класс / объект изображения.

У меня проблема с функцией Image :: save (...) и реализацией из Pixel :: grey () из RgbaGeneric.

Компилятор говорит, что я должен использовать черту From или Into. Но я не знаю, как должен выглядеть синтаксис. Все попытки заставить его работать не удаются.

mod image {
    use std::fmt;

    use std::path::Path;
    use std::io::Write;
    use std::fs::File;

    #[derive(Clone, Debug)]
    pub struct RgbaGeneric<T> {
        r: T, g: T, b: T, a: T,
    }

    trait Pixel<T> {
        fn red(&self) -> T;
        fn green(&self) -> T;
        fn blue(&self) -> T;
        fn alpha(&self) -> T;
        fn gray(&self) -> T;
    }

    impl<T> Pixel<T> for RgbaGeneric<T> {
        fn red(&self) -> T { return self.r;}
        fn green(&self) -> T { return self.g; }
        fn blue(&self) -> T { return self.b; }
        fn alpha(&self) -> T { return self.a; }
        fn gray(&self) -> T {
           return (self.r as f32 * 0.21 +
                   self.g as f32 * 0.72 +
                   self.b  as f32 * 0.07) as T;
        }
    }

    impl<T> RgbaGeneric<T> {
        pub fn new(r: T, g: T, b: T, a: T) -> RgbaGeneric<T> {
            RgbaGeneric { r, g, b, a }
        }
    }

    pub type RgbaU8 = RgbaGeneric<u8>;

    pub struct Image<T> {
        width: usize, height: usize, data: Vec<T>,
    }

    pub type ImageRgbaU8 = Image<RgbaU8>;

    impl<T> Image<T>
    where
        T: Clone + Pixel<T>
    {
        pub fn new(width: usize, height: usize, val: T) -> Image<T> {
            Image {
                width,
                height,
                data: vec![val; width * height],
            }
        }

        pub fn width(&self) -> usize { return self.width; }
        pub fn height(&self) -> usize { return self.height; }
        pub fn pixel_count(&self) -> usize {
            return self.width * self.height;
        }

        pub fn pixels(&self) -> &[T] { return self.data.as_slice(); }

        pub fn pixel(&self, x: usize, y: usize) -> &T {
            return &self.data[self.index(x, y)];
        }

        pub fn set_pixel(&mut self, x: usize, y: usize, pixel: T) {
            let idx = self.index(x, y);
            self.data[idx] = pixel;
        }

        pub fn save(&self, filename: &str) -> std::io::Result<()> {
            let path = Path::new(filename);
            let mut file = try!(File::create(&path));
            let header = format!("P6 {} {} 255\n", self.width, self.height);
            try!(file.write(header.as_bytes()));
            for y in 0..self.height() {
                for x in 0..self.width() {
                    let pix = self.pixel(x,y);
                    try!(file.write(pix.red()));
                    try!(file.write(pix.green()));
                    try!(file.write(pix.blue()));
                }
            }
            return Ok(());
        }

        fn index(&self, x: usize, y: usize) -> usize {
            return y * &self.width + x;
        }
    }
}

1 Ответ

0 голосов
/ 17 октября 2019

Реализация метода gray должна выглядеть следующим образом:

impl<T> Pixel<T> for RgbaGeneric<T> where
        f32: std::convert::From<T>,
        T: std::convert::From<f32>{
    fn red(&self) -> T { return self.r;}
    fn green(&self) -> T { return self.g; }
    fn blue(&self) -> T { return self.b; }
    fn alpha(&self) -> T { return self.a; }
    fn gray(&self) -> T {
       return (Into::<f32>::into(self.r) * 0.21 +
               Into::<f32>::into(self.g) * 0.72 +
               Into::<f32>::into(self.b) * 0.07).into();
    }
}

В заголовке блока мы говорим, что наш T может быть преобразован в тип f32 и обратно, а затем мыиспользуйте метод into(), потому что выражение as можно использовать только для преобразования между примитивными типами (компилятор подразумевает, что T может быть любого типа).

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