Anton Shramko
Senior Copypaster from StackOverflow
Язык программирования Rust
и его использование в Web
Докладчик Антон Шрамко
Почему я хочу рассказать о Rust?
What is Rust?
История создания
What is Rust?
Цели языка
What is Rust?
Какие цели не преследует Rust?
Обзор языка Rust
Базовые типы: Строка, Булев, Массив, Кортеж
fn main() {
let variable = "Hello world!";
let boolean: bool = true;
let array: [i32; 3] = [1,2,3]; // массив, фиксированный размер
let vec: Vec<i32> = vec![1,2,3]; // Вектор - расширяемый массив
let tuple: (i32, &str) = (21, "String"); // Кортеж
}
Обзор языка Rust
Базовые типы: Функции
fn void_function() {
println!("Hello World!");
}
fn number_square(number: i32) -> i32 {
number*number
}
// Функция обертка над макросом прерывания потока.
fn throw_panic() -> ! {
panic!("Oh, shit - unknown error");
}
// Базовая исполняемая функция
fn main() {
void_function();
// Вызов `fn number_square()`
let result_square = number_square(5);
println!("{}", result_square);
// Функция указатель - указывает на `fn number_square()`
let f_pointer: fn(i32) -> i32 = number_square;
let result_pointer = f_pointer(4);
println!("{}", result_pointer);
throw_panic();
}
Обзор языка Rust
Владения, Заимствования, Жизненный цикл
Обзор языка Rust
Пример: Владение
fn your_action() {
// присваиваем значение
let data = !vec[1,2,3];
// при выходе из области
// (по завершению работы функции)
// данные уничтожаются
}
сколько живут данные?
fn main() {
let data = vec![1,2,3];
// Присваивая data переменной bind
// Мы передаем ей право владения данными
let bind = data;
// Ошибка, право владения уже передано bind
println!("{}", data[1]);
}
присваивание = владение
fn bar(x: Vec<i32>) {
unimplemented!();
}
fn main() {
let vec: Vec<i32> = vec![1,2,3];
bar(vec);
// Ошибка, владение на данные уже передано
println!("{}", vec[1]);
}
Отдаем данные в функцию -
передаем владение
Обзор языка Rust
Пример: Заимствования
fn some_action(i: &Vec<i32>) {
unimplemented!();
}
fn main() {
let vec = vec![1,2,3];
// Вызываем с ссылочным аргументом
some_action(&vec);
// Данные все еще доступны!
println!("{}", vec[1]);
}
Ссылки - в функциях
fn main() {
let mut data = vec![1,2,3];
// Константные ссылки.
let other = &data;
let other2 = &data;
}
... В переменных
fn main() {
let mut data = vec![1,2,3];
// Мутабельная ссылка
let mut_link = &mut data;
}
fn main() {
let mut data = vec![1,2,3];
// Выдаст ошибку компиляции
let mut_link = &mut data;
let const_link = &data;
}
Правило:
Одна мутабельная ссылка или множество константных
Обзор языка Rust
Кратко о мутабельности...
fn main() {
// По умолчанию не мутабельны.
let const_data = vec![1,2,3];
// Мутабельные данные.
let mut data:i32 = 5;
data+=10;
// Мутабельная ссылка, на мутабельные данные.
let mut link = &mut data;
*link+=10;
}
К уже упомянутым в прошлом слайде правилам - коротко о мутабельности
Мутабельность полей
struct Obj {
field: i32,
// По умолчанию нельзя отдельное поле
// сделать мутабельным, только на уровне
// конкретного связывания.
// Это имитация мутабельности через Cell
mut_field: Cell<i32>
};
let object = Obj { field: 5, mut_field: Cell::new(10) };
// Присвоение нового значения
object.mut_field.set(25);
Обзор языка Rust
Перечисления, использование `match`
// Декларация перечисления
enum Enumeration {
AsStruct { a: i32, b: i32 },
Fn(i32),
BasicEnum
}
fn handle_fn(x: i32, y: i32) {
unimplemented!();
}
fn main() {
// Декларация переменной от перечисления
let data: Enumeration = Enumeration::AsStruct { x: 1, y: 1 };
// Обработка вариантов, от перечисления
match data {
// Проверка и отправление аргументов по ключу
Enumeration::AsStruct { a: i32, b: i32 } => handle_fn(a, b),
// Как функцию..
Enumeration::Fn(arg) => println!("{}", arg),
// Для остальных значений...
// match должен отработать все возможные варианты,
// если все варианты не обработаны - ошибка.
// Для этого существует параметр `_`
// для обработки остальных вариантов.
_ => unimplemented!()
};
}
Обзор языка Rust
В дополнение о `match`
fn main() {
let mut value = "Hello";
// Обработать разные значения
match value {
"Hello" => println!("Its 'Hello'!"),
_ => println!("Otherwise")
};
// Присвоение значения через обработку вариаций
let select_value = match value {
"Привет" => "Привет мир!",
"Hello" | "Hello!" => "Hello World!",
_ => "Кто тут с приветом?"
};
println!("{}", select_value);
// С получением ссылки
match value {
// Мутабельная ссылка
ref mut ref_link => println!("{}", ref_link)
};
// Вместе с структурами
struct ObjOne {
a: i32,
b: i32
}
let object = ObjOne { a: 1, b: 1 };
// Так..
match object {
ObjOne { a, b } => unimplemented!(),
};
// Или так..
match object {
ObjOne { a, ..} => unimplemented!(),
};
}
Обзор языка Rust
Структуры: Объявление, Методы, Цепочки вызовов
// Объявление структуры
struct Human {
firstname: String, // Объявление поля типа строка
lastname: String,
age: u32
}
// Имплементация методов для структуры
impl Human {
fn info(&self) -> String {
let info_value = format!("{} {}, возраст - {}", &self.firstname, &self.lastname, &self.age);
println!("Полная информация: {}", info_value);
String::from(info_value)
}
// Метод с мутабельной ссылой на экземпляр + реализация цепочки вызова
fn set_age(&mut self, age: u32) -> &mut Human {
self.age = age;
self
}
// Статический метод
fn new(firstname: &str, lastname: &str, age: u32) -> Human {
Human {
firstname: firstname.to_string(),
lastname: lastname.to_string(),
age: age
}
}
}
fn main() {
// Экземпляр структуры
let mut developer = Human {
lastname: "Шрамко".to_string(),
firstname: "Антон".to_string(),
age: 19
};
// Создание экземпляра из статического метода ::new
let mut manager = Human::new("Максим", "Мясоедов", 45);
manager.info();
println!("Имя: {}", developer.firstname); // Доступ к полям экземпляра
let info_string = developer.info(); // Использование метода
developer.set_age(25).info(); // Вызов цепочки
}
Обзор языка Rust
Generics
// Перечисление с заданным обобщенным типом
enum Human<N, A> {
Name(N),
Age(A)
}
// Структура с заданным обобщенным типом
struct Point<T> {
x: T,
y: T
}
// Функция с заданным обобщенным типом
fn generic_fn<A, N>(age: A, name: N) {
unimplemented!();
}
fn main() {
use Human::*;
// Использование перечисления с обобщенным типом
let name: Human<&str, i32> = Name("Антон");
let age: Human<&str, i32> = Age(19);
// Обработка вариаций - как обычных перечислений
match name {
Name(n) => println!("{}", n),
Age(a) => println!("{}", a)
}
// Для структур
let point:Point<i32> = Point { x: 0, y: 0 };
}
Обзор языка Rust
Traits: Интерфейсы, Обобщения
// Интерфейс с объявленной сигнатурой метода
trait Interface {
fn method(&self) -> u32;
}
// Другой интерфейс, но с зависимостью
// в реализации другого интерфейса
trait OtherInterface: Interface {
fn other_method(&self) -> u32;
}
struct Data {
field: u32
}
// Имплементация методов из интерфейса
impl Interface for Data {
fn method(&self) -> u32 {
self.field * 2
}
}
// Имплементация другого интерфейса
impl OtherInterface for Data {
fn other_method(&self) -> u32 {
self.field * 10
}
}
// Функция с заданным аргументом как реализации интерфейса
fn show_result<I: Interface>(result: &I) {
println!("{}", result.method());
}
// Функция требующая а аргументе имплементацию с
// реализацией нескольких интерфейсов
fn show_result_more_interfaces<I: Interface + OtherInterface>(result: &I) {
println!("{}", result.other_method());
}
fn main() {
let inst = Data { field: 2 };
// Вызов функции с ссылкой на экземпляр с реализацией
// интерфейса в качестве аргумента
show_result(&inst);
show_result_more_interfaces(&inst);
}
Обзор языка Rust
Перегрузка операций
// Импортируем из стандартной библиотеки интерфейс
// Из доступных операций: +, -, /, |, |=, и т.д
use std::ops::Add;
struct Overloading {
field: i32
}
// Имплементация интерфейса сложения для структуры
impl Add for Overloading {
type Output = Overloading;
// Реализация метода отвечающего за сложение
// и возвращающего конечную структуру
fn add(self, other: Overloading) -> Overloading {
Overloading { field: self.field + other.field }
}
}
fn main() {
// Объявляем структуры
let dataOne = Overloading { field: 5 };
let dataTwo = Overloading { field: 8 };
// Проводим операцию сложения
let result = dataOne + dataTwo;
// Результат = 13
println!("{}", result.field);
}
Дополнительные Возможности Rust
Макросы, FFI, Паралеллизм
FFI
Дополнительные возможности Rust
При желании можете посмотреть наиболее полный список примеров использования Rust в других языках тут:
FFI
Дополнительные возможности Rust
#[no_mangle] // Rust код
// объявляем публичную функцию, для внешнего использования.
pub extern fn double_input(input: i32) -> i32 {
input * 2
}
from ctypes import cdll
from sys import platform
if platform == 'darwin':
prefix = 'lib'
ext = 'dylib'
elif platform == 'win32':
prefix = ''
ext = 'dll'
else:
prefix = 'lib'
ext = 'so'
lib = cdll.LoadLibrary('target/debug/{}double_input.{}'.format(prefix, ext))
double_input = lib.double_input
input = 4
output = double_input(input)
print('{} * 2 = {}'.format(input, output))
Python
var ffi = require('ffi');
var lib = ffi.Library('target/debug/libdouble_input', {
'double_input': [ 'int', [ 'int' ] ]
});
var input = 4;
var output = lib.double_input(input);
console.log(input + " * 2 = " + output);
NodeJS
require 'ffi'
if RUBY_PLATFORM.include?('darwin')
EXT = 'dylib'
else
EXT = 'so'
end
module Hello
extend FFI::Library
ffi_lib 'target/debug/libdouble_input.' + EXT
attach_function :double_input, [ :int ], :int
end
input = 4
output = Hello.double_input(input)
puts "#{input} * 2 = #{output}"
Ruby
Макросы
Дополнительные возможности Rust
// Декларируем макрос vectors!
macro_rules! vectors {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
fn main() {
// Использование
let mut data = vectors![1,2,3];
}
Пример простого макроса для реализации `vec!`
WEB - Разработка и Rust
Обзор инструментов для написания Web сервисов на Rust
WEB - Разработка и Rust
Обзор инструментов для написания Web сервисов на Rust
WEB - Разработка и Rust
Pencil
Маленький и шустрый фреймворк для работы с Web на Rust. По утверждению авторов при написании этого инструмента они вдохновлялись микрофреймворком Flask из мира Python. Благодаря простой семантике и архитектуре, а также удобным "сахарным" возможностям, Pencil отлично подходит для начинающий разработчиков Rust - так как они могут без знания низко-уровневых тонкостей работы с http в rust, начать писать свои web-приложения и сервисы на коленке.
WEB - Разработка и Rust
Pencil
WEB - Разработка и Rust
Pencil
extern crate env_logger;
extern crate pencil;
extern crate log;
use std::collections::BTreeMap;
use pencil::{
PencilResult,
Response,
Request,
Pencil
};
fn home_handler(req: &mut Request) -> PencilResult {
let mut res_message = Response::from("Hello World");
Ok(res_message)
}
fn route_args_handler(req: &mut Request) -> PencilResult {
let firstname = req.view_args.get("firstname").unwrap();
let welcome = format!("welcome {}", firstname).into();
Ok(welcome)
}
fn template_handler(req: &mut Request) -> PencilResult {
let mut map_data = BTreeMap::new();
map_data.insert("value_one".to_string(), "value one".to_string());
map_data.insert("value_two".to_string(), "value two".to_string());
req.app.render_template("template.html", &map_data)
}
fn main() {
let mut app = Pencil::new("/");
app.set_debug(true);
app.set_log_level();
env_logger::init();
app.get("/", "home", home_handler);
app.get("/welcome/<firstname:string>", "welcome user as route param", route_args_handler);
app.get("/template", "response from template", template_handler);
app.run("127.0.0.1:9000");
}
WEB - Разработка и Rust
Nickel
WEB - Разработка и Rust
Nickel
#[macro_use] extern crate nickel;
extern crate regex;
use regex::Regex;
use nickel::{
MiddlewareResult,
HttpRouter,
Response,
Request,
Nickel,
Router,
};
fn main() {
let route_regexp = Regex::new("/hello/(?P<name>[a-zA-Z]+)").unwrap();
let mut server = Nickel::new();
server.utilize(module_for_nickel);
server
.get("/path", handler_as_fun)
.get("/hello", middleware!("Hello DevConf!"))
.get(route_regexp, middleware! { |request|
request.param("name").unwrap();
})
.get("/:arg", middleware! {|request|
let myArg = request.param("arg").unwrap();
format!("Вы ввели аргумент: {}", myArg)
});
server.listen("127.0.0.1:1488");
}
fn handler_as_fun<'mw>(req: &mut Request, res: Response<'mw>)
-> MiddlewareResult<'mw> {
res.send("Вот он ответ на запрос")
}
fn module_for_nickel() -> Router {
let mut router = Nickel::router();
router.post("/handle-form", middleware! { |req, res|
let form_data = try_with!(res, req.form_body());
...Ваши обработки
});
router
}
WEB - Разработка и Rust
Hyper, Iron
В завершение
Сравнение фреймворков + Посты про написание Web на Rust
Ламповая группа pro.Rust в Telegram
Мои контакты
Telegram: @tapok_satan
By Anton Shramko