2016-02-07 2 views
2

Я сегодня играл с 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", она пытается присвоить тип Sha1. Все типы, которые я намереваюсь использовать в этом утверждении соответствия, являются разработчиками признака Digest, поэтому я чувствую, что должен быть способ сделать это.

Я пробовал:

let mut hasher: Digest; 

Но это не сработало.

ответ

6

Похоже, вы хотите использовать trait objects. Ваш пример будет выглядеть примерно так:

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

Это будет работать только при определенных условиях (например, признак должен быть object safe), но я думаю, что это единственный способ сделать то, что вы хотите.

7

В дополнение к creating a boxed trait object вы также можете ссылаться на объект-объект. Это позволяет избежать выделения кучи:

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

Обратите внимание, что каждый реализатор только созданное в соответствующем плече матча, так что вы не делаете больше работы, чем вам нужно.

+1

Если бы я увидел этот код в C или C++, я бы сразу же отклонить его при просмотре коды, потому что, принимая ссылку на потенциально неинициализированное значение таит в себе опасность (следующей операции технического обслуживания, он будет дуть вверх). Здесь я смотрю на это и просто киваю. Это действительно так освобождает, когда вы можете доверять языку/компилятору. –

+0

@ MatthieuM. Разве это не правда! Я всегда с удовольствием помню, что в этом случае переменные также не должны быть «мутными». – Shepmaster

0

Спасибо за ответы. Я получил его для работы с 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(); 
} 
+1

КПП. Вы можете сделать матч немного менее шумным, назначив результат сопоставления 'hasher' [как это] (https://gist.github.com/fhartwig/d502370790fc3aa36450) (gist, потому что комментариев недостаточно места). – fjh

Смежные вопросы