如何有条件地为引用分配类型

jsh*_*ort 2 rust

我今天下午一直在玩Rust,并决定编写一个简单的哈希工具,可以做所有主要的消化算法.

我正在尝试做这样的事情(意图应该是显而易见的):

let mut hasher;
match alg {
    "md5" => { hasher = Md5::new() }
    "sha1" => { hasher = Sha1::new() }
    _ => { println!("Algorithm not implemented");
           process::exit(1); }
}
hash_file(&file_name, &mut hasher).unwrap();
Run Code Online (Sandbox Code Playgroud)

在编译上面时,由于第一次匹配,它假定hasher属于类型Md5并且在"sha1"匹配分支中失败,它尝试分配Sha1类型.我打算在这个匹配语句中使用的所有类型都是特征的实现者,Digest所以我觉得应该有办法做到这一点.

我试过了:

let mut hasher: Digest;
Run Code Online (Sandbox Code Playgroud)

但这也不起作用.

She*_*ter 7

除了创建盒装特征对象外,您还可以引用特征对象.这可以避免堆分配:

trait Hasher { fn hash(&self) -> u8 { 42 } }

struct Md5;
struct Sha1;

impl Hasher for Md5 {}
impl Hasher for Sha1 {}

fn hash_it(which: &str) {
    let (md5, sha1);

    let hasher: &Hasher = match which {
        "md5" => {
            md5 = Md5;
            &md5
        },
        "sha1" => {
            sha1 = Sha1;
            &sha1
        },
        _ => unreachable!("Nope"),
    };

    hasher.hash();
}

fn main() {
    hash_it("md5");
    hash_it("sha1");
}
Run Code Online (Sandbox Code Playgroud)

请注意,每个实现者只能在适当的匹配臂中创建,因此您的工作量不会超出您的需要.


fjh*_*fjh 6

听起来你想要使用特质对象.您的示例将大致如下所示:

let mut hasher;
match alg {
    "md5" => { hasher = Box::new(Md5::new()) as Box<Digest>}
    "sha1" => { hasher = Box::new(Sha1::new()) as Box<Digest>}
    _ => { println!("Algorithm not implemented");
           process::exit(1); }
}
hash_file(&file_name, &mut hasher).unwrap();
Run Code Online (Sandbox Code Playgroud)

这只能在某些条件下工作(例如,特性必须是对象安全的),但我认为这是你想要的唯一方法.