Как вызвать функцию с множеством разных типов?

#generics #types #rust #enums #overloading

#дженерики #типы #Ржавчина #перечисления #перегрузка

Вопрос:

Предположим, у нас есть следующее перечисление:

 #[derive(Serialize)]
#[serde(untagged)]
pub enum CustomType {
    Foo(Foo),
    Bar(Bar),
}
 

Для того, чтобы иметь функцию, которая ведет себя одинаково для разных типов параметров:

 fn my_function(my_param: amp;CustomType){
  // logic to use "my_param"
  // my_param is used for the handlebars crate, therefore requires to be Serde Serializable
 let source = // ...
 handlebars.render_template(amp;source, my_param).unwrap();
}
 

И мы хотим вызвать такую функцию в разных частях нашей программы следующим образом:

 fn function_a(bar: amp;Bar){
  my_function(CustomType::Bar(bar.clone()));
}

fn function_b(foo: amp;Foo){
  my_function(CustomType::Foo(foo.clone()));
}
 

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

Это правильный способ сделать это в Rust?

Ответ №1:

Вы можете создавать CustomType ссылки на использование вместо принадлежащих значений, если вы не хотите вызывать clone :

 use serde::{Serialize};

#[derive(Serialize)]
struct Foo(String);

#[derive(Serialize)]
struct Bar(String);

#[derive(Serialize)]
#[serde(untagged)]
enum CustomType<'a> {
    Foo(amp;'a Foo),
    Bar(amp;'a Bar),
}

fn my_function(my_param: amp;CustomType) {
    println!("serialized {}", serde_json::to_string(amp;my_param).unwrap());
}

fn func_foo(foo: amp;Foo) {
    my_function(amp;CustomType::Foo(foo));
}

fn func_bar(bar: amp;Bar) {
    my_function(amp;CustomType::Bar(bar));
}

fn main() {
    let foo = Foo("Foo".to_string());
    let bar = Bar("Bar".to_string());
    func_foo(amp;foo);
    func_bar(amp;bar);
}
 

игровая площадка

Однако, если CustomType существует единственная причина, по которой вы можете передавать Serializable типы, my_function тогда, вероятно, было бы проще просто создать my_function generic и принимать любые Serializable ссылки:

 use serde::{Serialize};

#[derive(Serialize)]
struct Foo(String);

#[derive(Serialize)]
struct Bar(String);

fn my_function<T: Serialize>(my_param: amp;T) {
    println!("serialized {}", serde_json::to_string(my_param).unwrap());
}

fn main() {
    let foo = Foo("Foo".to_string());
    let bar = Bar("Bar".to_string());
    my_function(amp;foo);
    my_function(amp;bar);
}
 

игровая площадка

Комментарии:

1. Да! Причина CustomType была именно для этой цели. Я не знал, что вы можете просто <T: Serialize> набивать (я пробовал <T> раньше, но остановился, поскольку он не был сериализуемым)