< 返回版块

ziyouwa 发表于 2022-01-18 21:50

Tags:genrics, trait

这是程序君的 Rust 培训(1)中关于泛型的练习,教程中作者使用了Vec作为encode后的返回对象,练习时自己做了修改,支持泛型。在更进一步拓宽适用范围时,遇到了问题。依然是不长的代码,问题在注释中。大概描述一下:泛型参数T,我知道它是某种特征数据的集合,我怎么把它合并在一起?这个时候T还没确定具体类型。

use std::io::Error;
pub trait Encoder {
    type Target;
    fn encode(&self) -> Result<Self::Target, Error>;
}

#[derive(Debug)]
pub struct User<Id, Data>
{
    id: Id,
    data: Data,
}

impl<Id, Data> User<Id, Data>
{
    pub fn new(id: Id, data: Data) -> Self {
        Self { id, data }
    }
}

impl<Id, Data, T> Encoder for User<Id, Data>
where
    Id: Encoder<Target = T>,
    Data: Encoder<Target = T>,
{
    type Target = T;
    fn encode(&self) -> Result<Self::Target, Error> {
        let mut ret = self.id.encode()?;
        let mut retdata = self.data.encode()?;

        // 问题在这里,该用什么方式来表达一个类似"+"的概念,
        // 可以实现类似数组或vec的合并这样的概念,达到ret+retdat的
        // 效果,以适应更广泛的类型,比如HashMap、Array等等。

        // ret.append(&mut retdata);
        // 如果把本例中的Self::Target换成Vec<Self::Target>
        // 然后把test中的type Target = u8,那么用append就可以
        
        Ok(ret)
    }
}


#[cfg(test)]
mod tests {
    use super::*;

    impl Encoder for u64 {
        type Target = Vec<u8>;
        fn encode(&self) -> Result<Self::Target, Error> {
            let ret = self.to_le_bytes().to_vec();
            Ok(ret)        
        }
    }
    
    impl Encoder for String {
        type Target = Vec<u8>;
        fn encode(&self) -> Result<Self::Target, Error> {
            let ret = self.as_bytes().to_vec();
            Ok(ret)
        }
    }
    #[test]
    fn test_name() {
        let t1 = User::new(1, "abcdef".to_string());
        println!("t1: {:?}", t1.encode().unwrap());
        let t2 = User::new("be".to_string(), 256);
        println!("t2: {:?}", t2.encode());
    }
}

评论区

写评论
作者 ziyouwa 2022-01-20 21:55

研究了半天,没明白怎么用这个,还请详细指点一下,谢谢!

--
👇
7sDream: 事实上,标准库里就有你需要的 Trait:std::iter::Extend

7sDream 2022-01-19 14:48

事实上,标准库里就有你需要的 Trait:std::iter::Extend

eweca-d 2022-01-19 09:59

这个不算自动推导吧。你再实现一个 impl Append for Vec<usize>也行啊。静态分发是你实现几个,到时候T就展开成几个。

--
👇
ziyouwa: 确实可以,非常感谢!居然可以自动推导T是Vec<u8>,NB!

--
👇
uno: 最简单的,就是再定义一个trait呗


pub trait Append {
    fn append(&mut self, data: Self);
}

impl Append for Vec<u8> {
    fn append(&mut self, mut data: Self) {
        self.append(&mut data)
    }
}


impl<Id, Data, T> Encoder for User<Id, Data>
where
    Id: Encoder<Target = T>,
    Data: Encoder<Target = T>,
    T: Append,
{
    type Target = T;
    fn encode(&self) -> Result<Self::Target, Error> {
        let mut ret = self.id.encode()?;
        let retdata = self.data.encode()?;
        ret.append(retdata);
        Ok(ret)
    }
}

作者 ziyouwa 2022-01-18 23:26

确实可以,非常感谢!居然可以自动推导T是Vec<u8>,NB!

--
👇
uno: 最简单的,就是再定义一个trait呗


pub trait Append {
    fn append(&mut self, data: Self);
}

impl Append for Vec<u8> {
    fn append(&mut self, mut data: Self) {
        self.append(&mut data)
    }
}


impl<Id, Data, T> Encoder for User<Id, Data>
where
    Id: Encoder<Target = T>,
    Data: Encoder<Target = T>,
    T: Append,
{
    type Target = T;
    fn encode(&self) -> Result<Self::Target, Error> {
        let mut ret = self.id.encode()?;
        let retdata = self.data.encode()?;
        ret.append(retdata);
        Ok(ret)
    }
}

uno 2022-01-18 22:56

最简单的,就是再定义一个trait呗


pub trait Append {
    fn append(&mut self, data: Self);
}

impl Append for Vec<u8> {
    fn append(&mut self, mut data: Self) {
        self.append(&mut data)
    }
}


impl<Id, Data, T> Encoder for User<Id, Data>
where
    Id: Encoder<Target = T>,
    Data: Encoder<Target = T>,
    T: Append,
{
    type Target = T;
    fn encode(&self) -> Result<Self::Target, Error> {
        let mut ret = self.id.encode()?;
        let retdata = self.data.encode()?;
        ret.append(retdata);
        Ok(ret)
    }
}

1 共 5 条评论, 1 页