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



今天下午我一直在玩 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();

编译上述内容时,由于第一个匹配项,它假定哈希器属于 Md5 类型,并且在 "sha1" match 分支中失败,它尝试分配Sha1类型。 我打算在此匹配语句中使用的所有类型都是特征Digest的实现者,所以我觉得应该有一种方法可以做到这一点。

我试过了:

let mut hasher: Digest;

但这也没有用。

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

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");
}

请注意,每个实现器仅在相应的匹配臂中创建,因此您不会执行超出需要的工作。

听起来你想使用特征对象。然后,您的示例将大致如下所示:

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();

这只在某些条件下有效(例如,特征必须是对象安全的),但我认为这是做你想做的事的唯一方法。

感谢您的回复。 我让它与 Box 一起工作,我仍然不完全理解,但我稍后会阅读。 最终工作代码:

fn process_hash(file_name: &str, alg: &str) {
    let valid_algorithms: Vec<&str> =
        vec!["md5", "sha1", "sha224", "sha256", "sha384", "sha512", "sha512224",
             "sha512256", "blake2b-64", "ripemd160", "whirlpool"];
    let mut hasher: Box<Digest>;
    match alg {
        "md5" => { hasher = Box::new(Md5::new()) }
        "sha1" => { hasher = Box::new(Sha1::new()) }
        "sha224" => { hasher = Box::new(Sha224::new()) }
        "sha256" => { hasher = Box::new(Sha256::new()) }
        "sha384" => { hasher = Box::new(Sha384::new()) }
        "sha512" => { hasher = Box::new(Sha512::new()) }
        "sha512224" => { hasher = Box::new(Sha512Trunc224::new()) }
        "sha512256" => { hasher = Box::new(Sha512Trunc256::new()) }
        "blake2b-64" => { hasher = Box::new(Blake2b::new(64)) }
        "ripemd160" => { hasher = Box::new(Ripemd160::new()) }
        "whirlpool" => { hasher = Box::new(Whirlpool::new()) }
        _ => { println!("Algorithm not implemented");
               println!("Valid choices: {}", valid_algorithms.join(" "));
               process::exit(1); }
    }
    hash_file(&file_name, &mut *hasher).unwrap();
}

最新更新