2017-01-28 10 views
1

Я хочу создать экземпляр переменной, которую я передам в функцию, которая принимает T: Write. Она будет определяться следующим образом:Как определить переменную, которая соответствует признаку в Rust?

let outputFile = match matches.opt_str("o") { 
    Some(fileName) => File::create(fileName).expect("could not open output file"), 
    None => std::io::stdout() 
}; 

В настоящее время, компилятор будет жаловаться на несовпадающих типов в руках (File против Stdout). Все, что я хочу, - объявить outputFile как нечто, что я могу назвать любым способом из черты Write, и ничего больше.

Может ли Rust разрешить это делать или мне нужно привести все это выражение match в качестве параметра, который нужно передать в эту функцию?

ответ

4

Если вы хотите вернуть один из двух (или более) отдельных типов, реализующих черту, то вам необходимо вернуть trait object.

В этом случае вам нужно вернуть значение, чтобы владеть объектом (иначе иначе File будет уничтожен до конца match), поэтому имеет смысл использовать Box<Write>. Такие объекты, как &Write и Box<Write>, являются «жирными» указателями, которые включают в себя как указатель на структуру (File, так и Stdout), а также указатель на таблицу vtable, которая описывает, как реализовать Write. Важно отметить, что Box<Write> и &Write автоматически реализуют Write.

Вот рабочая версия (playground):

fn get_writer(f: Option<&str>) -> Box<Write> { 
    match f { 
     Some(file_name) => Box::new(File::create(file_name).expect("could not open output file")), 
     None => Box::new(std::io::stdout()), 
    } 
} 

Я сделал несколько изменений из кода:

  • добавленную стоимость Box<Write> возврата (без функции вам может понадобиться имеют let outputFile: Box<Write> = ...; не имея определенного здесь типа, компилятор не сможет сделать вывод о том, что ему необходимо принудить два типа к общему Box<Write>. Как только компилятор знает, что ему нужно Box<Write>, он может coerce a Box<File> до Box<Write>.

  • Вставка этих двух результатов.

  • Переименован fileName в file_name, чтобы соответствовать соглашениям о ржавчине (и отключить предупреждение).