Pull to refresh

Comments 8

Не упомянули, но для меня полезным являются ещё trait's From и Into. У Rust нет перегрузки методов/функций и это заставляет плодить методы там, где казалось бы для этого нет особых причин.

Например вы хотите сделать одну функцию которая бы могла принимать на вход строку, массив строк или ничего. По умолчанию нужно делать три разных функции. Но с trait From это можно сделать лучше.

Пример:

pub enum ArgStrings {
    None,
    String(String),
    List(Vec<String>)
}

impl From<&str> for ArgStrings {
    fn from(value: &str) -> Self {
        ArgStrings::String(value.to_string())
    }
}

impl From<Vec<&str>> for ArgStrings {
    fn from(value: Vec<&str>) -> Self {
        ArgStrings::List(value.iter().map(|x| x.to_string()).collect())
    }
}

impl From<Option<()>> for ArgStrings {
    fn from(_value: Option<()>) -> Self {
        ArgStrings::None
    }
}

Теперь объявляем нашу функцию:

    pub fn has_label<T: Into<ArgStrings>>(mut self, labels: T) -> GraphTraversalSource<'a> {
        let labels: Option<Vec<String>> = match labels.into() {
            ArgStrings::None => None,
            ArgStrings::String(v) => Some(vec![v]),
            ArgStrings::List(v) => Some(v),
        };
        ...
    }

И можем вызывать ее таким образом:

.has_label(None);
.has_label("product");
.has_label(ver!["product", "discount", "bundle"]);

Получилось аккуратненько. Тоже самое, но в другую сторону можно проверить с помощью trait Into.

Если логика для всех трёх случаев имеет мало общего (а, скорее всего, оно так и есть), то можно объявить трейт AsLabelList с единственной функцией has_label реализовать его для всех нужных типов. Тогда можно указать для «единой» функции требование трейта и пробрасывать вызов дальше. Это отлично оптимизируется, а ещё позволяет пользователю реализовывать трейт для своих типов, которые тоже можно будет передать в нашу функцию

Хитро! Напомню, что в расте нет перегрузки функций (как в Си), так что пришлось бы делать три функции с разными именами (или создавать zero-size структуру и писать полиморфные (?) статические методы).

Ещё есть забавный и иногда полезный return type polymorphism - в том числе для перегрузки методов с одинаковыми именами, если я не ошибаюсь.

Побуду занудой: в С перегрузки функций нет, только в С++.

Побуду еще большим занудой, с gcc магией есть не только перегрузки функций, но даже лямбды)

Sign up to leave a comment.