为两种截然不同的类型而与Rust泛型斗争

1bqhqjot  于 2023-02-04  发布在  其他
关注(0)|答案(2)|浏览(108)

我正在编写一个用Vec<u16>表示位置的游戏。我正在为一个穷举dfs缓存最佳移动和丢失位置。最佳位置返回一个Guess结构体,其中包含几个u16成员。而丢失的位置包括一个u16,它报告了失败的深度,我使用了一个HashMap<Vec<u16>,Guess>和一个HashMap<Vec<u16>,u16>来存储和检索这些。有许多重叠的函数,包括文件保存和恢复,所以我尝试实现一个通用的Cache结构来管理这两种类型,如下所示:

trait Cacheable {}
impl Cacheable for u16 {}
impl Cacheable for Guess {}

pub struct Cache<T: Cacheable> {
    hashmap: Vec<HashMap<Vec<u16>, T>>,
    filename: String,
    items_added: u32,
}

当从磁盘加载HashMap时,我需要恢复hashmap值,但是我找不到一种方法来创建一个从输入Vec<u16>返回类型T的函数。

impl Cache<u16> {
    fn make_value(data: &Vec<u16>) -> u16 {
        data[0]
    }
}

impl Cache<Guess> {
    fn make_value(data: &Vec<u16>) -> Guess {
        Guess::new_from_vec(data)
    }
}

但是当我尝试使用value = Cache::make_value(&data);时,编译器抱怨同一个函数使用了重复的impl

h79rfbju

h79rfbju1#

为什么要在impl Cache中编写泛型依赖的make_value
你已经有了一个表示可缓存值的trait,所以用这个trait来表示不同的行为,否则你为什么要有这个trait呢?
还有,吹毛求疵:使用&Vec<u16>作为函数参数是一种反模式。请改用&[u16]。它完全兼容并且更通用。没有理由需要使用&Vec<u16>来代替。

use std::collections::HashMap;

#[derive(Debug)]
struct Guess {
    data: Vec<u16>,
}
impl Guess {
    fn new_from_slice(data: &[u16]) -> Self {
        Self {
            data: data.to_vec(),
        }
    }
}

pub trait Cacheable: Sized {
    fn make_value(data: &[u16]) -> Self;
}

impl Cacheable for u16 {
    fn make_value(data: &[u16]) -> u16 {
        data[0]
    }
}
impl Cacheable for Guess {
    fn make_value(data: &[u16]) -> Guess {
        Guess::new_from_slice(data)
    }
}

pub struct Cache<T: Cacheable> {
    hashmap: Vec<HashMap<Vec<u16>, T>>,
    filename: String,
    items_added: u32,
}

impl<T: Cacheable> Cache<T> {
    fn make_value(data: &[u16]) -> T {
        T::make_value(data)
    }
}

fn main() {
    let data = vec![1, 2, 3];

    let cached_u16: u16 = Cache::make_value(&data);
    let cached_guess: Guess = Cache::make_value(&data);

    dbg!(cached_u16);
    dbg!(cached_guess);
}
[src/main.rs:48] cached_u16 = 1
[src/main.rs:49] cached_guess = Guess {
    data: [
        1,
        2,
        3,
    ],
}
ykejflvf

ykejflvf2#

我意识到我需要在trait impl中实现特定于类型的函数,我只是使用trait来限制泛型的适用性,而不是上面所做的,我需要这样做:

trait Cacheable<T> {
    fn make_value(data: &Vec<u16>) -> T
}
impl Cacheable<u16> for u16 {
    fn make_value(data: &Vec<u16>) -> u16 {
        data[0]
    }
}
impl Cacheable<Guess> for Guess {
    fn make_value(data: &Vec<u16>) -> Guess {
        Guess::new_from_vec(data)
    }
}

还没有测试,但它现在编译,所以我很乐观。感谢所有的投入。

相关问题