Rust: полиморфные вызовы структур в векторе - PullRequest
0 голосов
/ 22 декабря 2018

Я полный новичок в Rust и пытаюсь понять основы языка.

Рассмотрим следующую черту

trait Function {
    fn value(&self, arg: &[f64]) -> f64;
}

и две структуры, реализующиеit:

struct Add {}

struct Multiply {}

impl Function for Add {
    fn value(&self, arg: &[f64]) -> f64 {
        arg[0] + arg[1]
    }
}

impl Function for Multiply {
    fn value(&self, arg: &[f64]) -> f64 {
        arg[0] * arg[1]
    }
}

В моей функции main() я хочу сгруппировать два экземпляра Add и Multiply в векторе, а затем вызвать метод value.Следующие работы:

fn main() {
    let x = vec![1.0, 2.0];
    let funcs: Vec<&dyn Function> = vec![&Add {}, &Multiply {}];

    for f in funcs {
        println!("{}", f.value(&x));
    }
}

И так же:

fn main() {
    let x = vec![1.0, 2.0];
    let funcs: Vec<Box<dyn Function>> = vec![Box::new(Add {}), Box::new(Multiply {})];

    for f in funcs {
        println!("{}", f.value(&x));
    }
}

Есть ли лучший / менее многословный способ?Могу ли я обернуть экземпляры в Box?Что такое вынос с чертами объектов в этом случае?

1 Ответ

0 голосов
/ 22 декабря 2018

Есть ли лучший / менее многословный способ?

На самом деле не существует способа сделать это менее многословным.Поскольку вы используете объекты признаков, вам нужно сообщить компилятору, что элементы векторов dyn Function, а не конкретный тип.Компилятор не может просто сделать вывод, что вы имели в виду dyn Function объекты признаков, потому что могли существовать другие признаки, которые оба Add и Multiply реализуют.

Вы не можете абстрагировать вызовы к Box::new или.Чтобы это работало, вам нужно как-то отобразить разнородную коллекцию, что невозможно в Rust.Однако, если вы много пишете об этом, вы можете рассмотреть возможность добавления вспомогательных функций конструктора для каждого конкретного impl:

impl Add {
    fn new() -> Add {
        Add {}
    }

    fn new_boxed() -> Box<Add> {
        Box::new(Add::new())
    }
}

Идиоматично включать конструктор new везде, где это возможно, но это также распространеновключите альтернативные удобные конструкторы.

Это делает построение вектора немного менее шумным:

let funcs: Vec<Box<dyn Function>> = vec!(Add::new_boxed(), Multiply::new_boxed()));

Что такое вынос с объектами признаков в этом случае?

При использовании динамической диспетчеризации всегда наблюдается небольшое снижение производительности.Если все ваши объекты одного типа, они могут быть плотно упакованы в памяти, что может быть намного быстрее для итерации.В общем, я бы не стал сильно беспокоиться об этом, если вы не создаете библиотечный ящик или если вы действительно хотите выжать последнюю наносекунду производительности.

...