Краткий обзор Rust с простыми примерами для демонстрации концепций

Код этого фрагмента доступен на GitHub.

Структуры

struct в Rust - это то же самое, что Class в Java или struct в Golang. Это именованный тип, которому вы можете назначить состояние (атрибуты / поля) и поведение (методы / функции).

Вот struct с полями:

struct Programmer {
    email: String,
    github: String,
    blog: String,
}

Чтобы создать экземпляр Programmer, вы можете просто:

let pg1 = Programmer {
        email: String::from("[email protected]"),
        github: String::from("https://github.com/abhirockzz"),
        blog: String::from("https://dev.to/abhirockzz"),
    };

Методы

Методы - это поведение, связанное с данным типом. Первым параметром в методе всегда является self, который представляет экземпляр, для которого метод вызывается.

Давайте добавим метод в Programmer. Для этого нам понадобится блок impl:

impl Programmer {
    fn is_same_as(&self, other: Programmer) -> bool {
        return self.email == other.email;
    }
}

Метод is_same_as принимает ссылку на вызываемый экземпляр (&self) и другой Programmer экземпляр. Чтобы вызвать его, создайте еще один экземпляр Programmer (pg2) и сравните с ним pg1.

я типы

Мы использовали &self в качестве параметра для is_same_as. Таким образом, мы передадим только ссылку, а функция не будет владеть значением - только заимствует его (см. Rust: Владение и заимствование). Также можно использовать self и &mut self.

Вы можете использовать self, но будьте осторожны, так как он передаст право собственности функции. Посмотрим на эту функцию.

Вы можете вызвать его, используя экземпляр pg2 как таковой pg2.details();, и вы должны вернуться:

Email: [email protected],
GitHub repo: https://github.com/abhirockzz,
Blog: https://medium.com/@abhishek1987

Если вы снова попытаетесь использовать pg2 (например, pg2.is_same_as(&pg1);), вы получите ошибку компилятора:

error[E0382]: borrow of moved value: `pg2`

Если вы хотите изменить экземпляр Programmer, используйте &mut self следующим образом:

Если вы не отметите переменную (pg3) как mut (изменяемая), вы получите ошибку компилятора:

error[E0596]: cannot borrow `pg2` as mutable, as it is not declared as mutable

Другие функции, связанные со структурой

Вы можете добавить associated functions, которые связаны с экземпляром struct - думайте об этом как о static методе в Java. Они обычно используются в качестве конструкторов.

Это отличается от того, как конструкторы используются в Java, но похоже на подход Go.

Вот как это можно использовать:

let pg3 = Programmer::new(
        String::from("[email protected]"),
        String::from("https://github.com/abhirockzz"),
        String::from("https://medium.com/@abhishek1987"),
    );

Обратите внимание, что мы используем _38 _ (_ 39_) для доступа к associated членам struct (в данном случае функции).

Можно использовать разные impl блоки для одного и того же struct.

Черты

Trait в Rust похож на Interface в других языках, таких как Java и т. Д. Они помогают определить один или несколько наборов поведения, которые могут быть implemented разными типами по-своему.

Реализация Trait в Rust очень похожа на то, как это делается в Java. В Java вы можете использовать ключевое слово implements, в то время как Rust использует impl.

Между интерфейсом и типом, реализующим его, существует явная связь. Это сильно отличается от Go, где вам не нужно объявлять, какой интерфейс вы реализуете - если вы реализовали требуемое поведение, компилятор будет доволен.

Начнем с определения Trait.

trait PrettyPrint {
    fn pretty_print(&self);
}

И реализуем это.

Не беспокойтесь о деталях примера, просто сосредоточьтесь на ключевых частях.

Это довольно просто: используйте ключевое слово impl, за которым следует признак, который вы реализуете, и укажите тип, реализующий признак, после ключевого слова for. Теперь вы можете использовать его, как и любой другой метод:

let pg = Programmer::new(...);
pg.pretty_print();

Используйте черту standard из библиотеки

Стандартная библиотека Rust предоставляет несколько Trait библиотек, которые вы можете использовать. Реализуем черту std::fmt::Display. Это для вывода, ориентированного на пользователя, например мы можем использовать его с макросом println!.

Не беспокойтесь о специфике реализации и типах, таких как std::fmt::Formatter и т. Д. А пока просто поймите, что вы можете реализовать трейт Display из модуля Rust std::fmt.

С этого момента вы можете использовать экземпляр Programmer с println! как таковой.

let another_pg = Programmer::new(...);
println!("programmer details: {}", another_pg);
//output:
programmer details: ([email protected], https://github.com/abhirockzz, https://medium.com/@abhishek1987)

Халява

Rust предоставляет множество полезных функций, которые вы можете использовать бесплатно! Это означает, что вам не нужно реализовывать их явно (вы, конечно, можете, если хотите). Вы делаете это с помощью атрибута #[derive].

attribute - это просто часть метаданных, которую вы можете применять к структурам и т. Д. Они напоминают мне аннотации Java.

Вот пример. Мы можем применить черту std::fmt::Debug к Programmer, а затем использовать ее с println!.

Это похоже на то, что мы сделали с Display, но ключевое отличие состоит в том, что derive Display невозможно (у вас есть для его реализации). Все, что вам нужно сделать, это добавить #[derive(Debug)] в структуру Programmer:

Просто используйте формат :?, чтобы использовать функции Debug по умолчанию.

Если вы добавите # в смесь, вы получите красивую печать бесплатно… ура!

Есть и другие полезные свойства, такие как Eq, Clone, PartialEq и т. Д., Которые вы можете derive.

Использование черт

Чтобы воспользоваться чертами, вы должны иметь возможность принимать и возвращать их из функций и методов, чтобы использовать «общее» поведение. Мы можем написать функцию, которая принимает тип, реализующий PrettyPrint.

Обратите внимание, что к параметру добавлен impl.

Также можно вернуть PrettyPrint:

Методы по умолчанию

Можно предоставить реализации методов по умолчанию внутри самого признака (при необходимости их можно переопределить). Эти методы также могут вызывать другие методы признаков (по умолчанию или нет).

Следите за новостями в другом блоге об основах Rust!