70
Rust: абстракции и безопасность, совершенно бесплатно Владимир Матвеев [email protected] 1 / 70

Rust: абстракции и безопасность, совершенно бесплатно

  • Upload
    open-it

  • View
    333

  • Download
    4

Embed Size (px)

DESCRIPTION

Владимир Матвеев: "Rust: абстракции и безопасность, совершенно бесплатно" (Обзор языка Rust: для чего он предназначен, его ключевые особенности, инфраструктура)

Citation preview

Page 1: Rust: абстракции и безопасность, совершенно бесплатно

Rust: абстракции и безопасность,совершенно бесплатно

Владимир Матвеев[email protected]

1 / 70

Page 2: Rust: абстракции и безопасность, совершенно бесплатно

Место

Близко к железу, но большой простор для ошибок:

СС++

Высокоуровневые, безопасные, но дают меньше контроля:

JavaHaskellPythonRubyJSGo...

2 / 70

Page 3: Rust: абстракции и безопасность, совершенно бесплатно

Классы ошибок

В C++:

Висящие указателиДоступ за границами массивовУтечки памятиПереполнение буфераUse-after-freeГонки данныхIterator invalidation

В Java:

NullPointerExceptionConcurrentModificationExceptionУтечки памяти (!)

3 / 70

Page 4: Rust: абстракции и безопасность, совершенно бесплатно

Выводы

Просто «Best practices» недостаточноБезопасность с помощью идиом/гайдов не обеспечитьКомпилятор должен сам отклонять небезопасныепрограммы

4 / 70

Page 5: Rust: абстракции и безопасность, совершенно бесплатно

Решение

Rust обеспечивает безопасность работы с памятью спомощью мощного статического анализаНет явного управления памятью, компилятор отслеживаеталлокации и деаллокацииЕсли программа компилируется, то она работает спамятью безопасноZero-cost abstractions, как в С++Вывод типов сильно помогает как при написании, так ипри чтении

5 / 70

Page 6: Rust: абстракции и безопасность, совершенно бесплатно

История

Появился как личный проектС 2009 спонсируется Mozilla ResearchПервый анонс в 2010 годуВ 2011 компилирует себяВ 2012 выходит версия 0.1...

6 / 70

Page 7: Rust: абстракции и безопасность, совершенно бесплатно

Будущее

Начало 2015 - релиз первой стабильной версииСтабилизация языка и APIЦентральный репозиторий пакетовМножество отложенных фич

Типы высшего порядкаЕщё более продвинутые макросыВычисления при компиляции...

7 / 70

Page 8: Rust: абстракции и безопасность, совершенно бесплатно

Rust

компилируемый (LLVM)быстрыйбезопасныйсо статической типизациейс выводом типовс бесплатными абстракциямис функциональными элементамиминимальный рантайм (либо его отсутствие)...

8 / 70

Page 9: Rust: абстракции и безопасность, совершенно бесплатно

Кроссплатформенность

LLVM => множество платформ

Официально поддерживаются:

LinuxMac OS XWin32/Win64

Также работает под Android и iOS

9 / 70

Page 10: Rust: абстракции и безопасность, совершенно бесплатно

Типы данных

10 / 70

Page 11: Rust: абстракции и безопасность, совершенно бесплатно

Встроенные типы

C фиксированным размером:i8, i16, i32, i64, u8, u16, u32, u64, f32, f64

С платформозависимым размером: int, uintМассивы и строки: [u8, ..16], [i16], strКортежи: (), (u16,), (f64, f64)Ссылки: &mut T, &T«Сырые» указатели: *mut T, *const TУказатели на функции:fn(u32, u32), extern "C" fn(u16) -> u16

Замыкания: |int, int| -> int, proc(f64) -> u64

11 / 70

Page 12: Rust: абстракции и безопасность, совершенно бесплатно

Срезы

let array: [u8, ..16] = [0, ..16];let slice: &[u8] = &array;println!("{}", slice.len()); // 16

Строковые срезы (и вообще строки) всегда в UTF-8:

let s: &str = "abcde";let str_buf: String = s.into_string();

12 / 70

Page 13: Rust: абстракции и безопасность, совершенно бесплатно

Структуры

Обычные:

struct Point { x: f64, y: f64}

Tuple structs:

struct Point(f64, f64);

Newtypes:

struct Distance(uint);

13 / 70

Page 14: Rust: абстракции и безопасность, совершенно бесплатно

Перечисления

Как в C:

enum Direction { North, West = 123, South = 324, East}

Как в Haskell:

enum Option<T> { Some(T), None}

14 / 70

Page 15: Rust: абстракции и безопасность, совершенно бесплатно

Перечисления

С вариантами-структурами:

enum Event { KeyPress { keycode: uint, modifiers: uint }, MouseMove { x: u32, y: u32 }, ...}

15 / 70

Page 16: Rust: абстракции и безопасность, совершенно бесплатно

Основные элементы языка

16 / 70

Page 17: Rust: абстракции и безопасность, совершенно бесплатно

С-подобный синтаксис

fn main() { for i in range(0, 10) { println!("Hello world!"); }}

Всё — выражения

let m = if x % 2 == 0 { "even" } else { "odd" };

Вывод типов

fn take_int(x: int) { ... }let x = 10;take_int(x); // x is inferred as int

17 / 70

Page 18: Rust: абстракции и безопасность, совершенно бесплатно

Циклы

let (mut x, mut y) = (random_int(), random_int());loop { x += 3; if x < y { continue; } y -= 3; if x > y { break; }}

let mut n = 0;while n < 100 { n += 1; if n % 5 == 2 { n += 13; }}

18 / 70

Page 19: Rust: абстракции и безопасность, совершенно бесплатно

Сопоставление с образцом

switch как в C:

let x: uint = 10;let name = match x { 1 => "one", 2 => "two", _ => "many"};

Деструктуризация как в Haskell:

let mut f = File::open("/tmp/input");match f.read_to_end() { Ok(content) => println!("{} bytes", content.len()), Err(e) => println!("Error: {}", e)}

19 / 70

Page 20: Rust: абстракции и безопасность, совершенно бесплатно

Сопоставление с образцом

Для срезов:

let x = [1, 2, 3, 4];match x.as_slice() { [1, x, ..rest] => { println!("2nd: {}, all others: {}", x, rest); } _ => println!("Something else")}

При объявлении переменных и параметров:

fn sum_tuple((x, y): (int, int)) -> int { x + y}

20 / 70

Page 21: Rust: абстракции и безопасность, совершенно бесплатно

Сопоставление с образцом

if let, while let из Swift:

if let Some(r) = from_str::<int>("12345") { println!("String \"12345\" is {}", r);}

while let Ok(token) = next_token() { println!("Next token: {}", token);}

21 / 70

Page 22: Rust: абстракции и безопасность, совершенно бесплатно

Функции

fn multiply(left: uint, right: uint) -> uint { left + right}

#[no_mangle]pub extern fn visible_from_c(arg: u32) -> u32 { arg + arg}

22 / 70

Page 23: Rust: абстракции и безопасность, совершенно бесплатно

Методы

struct Counter { base: u64}

impl Counter { fn new(base: u64) -> Counter { Counter { base: base } }

fn next(&mut self) -> u64 { let t = self.base; self.base += 1; return t; }}

let mut counter = Counter::new(10);println!("{} -> {} -> {}", counter.next(), counter.next(), counter.next());

23 / 70

Page 24: Rust: абстракции и безопасность, совершенно бесплатно

Полиморфизм

24 / 70

Page 25: Rust: абстракции и безопасность, совершенно бесплатно

Дженерики

Как шаблоны в C++:

enum Option<T> { None, Some(T)}

fn unwrap_or<T>(opt: Option<T>, default: T) -> T { match opt { Some(value) => value, None => default }}

println!("{}", unwrap_or(Some(10), 20)); // 10println!("{}", unwrap_or(None, "abcde")); // abcde

25 / 70

Page 26: Rust: абстракции и безопасность, совершенно бесплатно

Дженерики

enum Option<T> { None, Some(T)}

impl<T> Option<T> { fn unwrap_or(self, default: T) -> T { match self { Some(value) => value, None => other } }}

println!("{}", Some(10).unwrap_or(20)); // 10println!("{}", None.unwrap_or("abcde")); // abcde

26 / 70

Page 27: Rust: абстракции и безопасность, совершенно бесплатно

Трейты

Ограничения на ти́повые переменные:

trait Display { fn display(&self) -> String;}

impl Display for int { fn display(&self) -> String { self.to_string() }}

impl Display for String { fn display(&self) -> String { self.clone() }}

fn print_twice<T: Display>(value: &T) { let s = value.display(); println!("{} {}", value, value);}

27 / 70

Page 28: Rust: абстракции и безопасность, совершенно бесплатно

Трейты

trait Add<RHS, Result> { fn add(&self, rhs: &RHS) -> Result; }trait Mul<RHS, Result> { fn mul(&self, rhs: &RHS) -> Result; }

fn lin_map<T: Add<T, T>+Mul<T, T>>(a: T, b: T, x: T) -> T { a*x + b}

// more readablefn lin_map<T>(a: T, b: T, x: T) -> T where T: Add<T, T> + Mul<T, T> { a*x + b}

28 / 70

Page 29: Rust: абстракции и безопасность, совершенно бесплатно

Трейты

Ср. с классами типов в Haskell:

class Display a where display :: a -> String

class Add a rhs result where add :: a -> rhs -> result

А также реализации для произвольных типов, множественнаядиспетчеризация, ассоциированные типы, etc.

29 / 70

Page 30: Rust: абстракции и безопасность, совершенно бесплатно

Trait objects

fn print_slice<T: Show>(items: &[T]) { for item in items.iter() { println!("{} ", item); }}

print_slice(&[1i, 2i, 3i]); // okprint_slice(&["a", "b"]); // okprint_slice(&[1i, 2i, "a"]); // compilation error :(

30 / 70

Page 31: Rust: абстракции и безопасность, совершенно бесплатно

Trait objects

Трейты как интерфейсы:

fn print_slice(items: &[&Show]) { for item in items.iter() { println!("{}", item); }}

print_slice(&[&1i, &2i, &3i]); // okprint_slice(&[&"a", &"b"]); // okprint_slice(&[&1i, &2i, &"a"]); // ok!

31 / 70

Page 32: Rust: абстракции и безопасность, совершенно бесплатно

Трейты

Zero-cost on-demand abstraction:

Ограничения на дженерики — статический полиморфизм,мономорфизация, инлайнингTrait objects — динамический полиморфизм, виртуальныетаблицы, позднее связываниеCost is explicit — сразу видно, где именно появляетсяоверхед

32 / 70

Page 33: Rust: абстракции и безопасность, совершенно бесплатно

Владение данными

33 / 70

Page 34: Rust: абстракции и безопасность, совершенно бесплатно

Ownership and borrowing

Владение и заимствование — ключевые концепции Rust

С помощью статических проверок на их основе компиляторспособен предотвратить огромное число ошибок управленияресурсами: use-after-free, double-free, iterator invalidation, dataraces

Владение данными основывается на теории линейных типов(linear types). Авторы Rust вдохновлялись языками Clean иCyclone; см. также unique_ptr в C++

34 / 70

Page 35: Rust: абстракции и безопасность, совершенно бесплатно

Ownership

{ int *x = malloc(sizeof(int));

// do stuff *x = 5;

free(x);}

35 / 70

Page 36: Rust: абстракции и безопасность, совершенно бесплатно

Ownership

{ int *x = malloc(sizeof(int));

// do stuff *x = 5;

free(x);}

{ let x = box 5;}

36 / 70

Page 37: Rust: абстракции и безопасность, совершенно бесплатно

Ownership

fn add_one(mut num: Box<int>) { *num += 1;}

let x = box 5i;

add_one(x);

println!("{}", x); // ! error: use of moved value: x

Move-семантика в действии!

37 / 70

Page 38: Rust: абстракции и безопасность, совершенно бесплатно

Ownership

fn add_one(mut num: Box<int>) -> Box<int> { *num += 1; num}

let x = box 5i;

let y = add_one(x);

println!("{}", y); // 6

38 / 70

Page 39: Rust: абстракции и безопасность, совершенно бесплатно

Copy

Некоторые типы реализуют трейт Copy; они автоматическикопируются вместо перемещения:

let x: int = 10;let y = x;println!("{}", x);

39 / 70

Page 40: Rust: абстракции и безопасность, совершенно бесплатно

RAII

Владение данными + move semantics + деструкторы =безопасный RAII

{ let mut f = File::open(&Path::new("/some/path")).unwrap(); // work with file ...} // f's destructor is called here // (unless it is moved somewhere else)

Но move semantics подразумевает передачу права владения,что возможно далеко не всегда:

let mut f = File::open(&Path::new("/some/path")).unwrap();let buf = [0u8, ..128];f.read(buf).unwrap();println!("{}", buf); // ! use of moved value: buf

40 / 70

Page 41: Rust: абстракции и безопасность, совершенно бесплатно

Borrowing

Владелец данных может предоставить к ним доступ спомощью ссылок:

fn with_one(num: &int) -> int { *num + 1}

let x = box 5i;

println!("{}", with_one(&*x)); // 6

41 / 70

Page 42: Rust: абстракции и безопасность, совершенно бесплатно

Borrowing

&T — разделяемые/иммутабельные (shared/immutable)&mut T — неразделяемые/мутабельные (exclusive/mutable)

let x = 10i;let p1 = &x;let p2 = &x; // ok

let mut x = 10i;let p1 = &mut x;let p2 = &x; // ! cannot borrow x as immutable because // ! it is also borrowed as mutable

let mut x = 10i;let p1 = &mut x;let p2 = &mut x; // ! cannot borrow x as mutable // ! more than once at a time

42 / 70

Page 43: Rust: абстракции и безопасность, совершенно бесплатно

Borrowing and mutability

«Эксклюзивность» мутабельных ссылок исключает оченьбольшой класс ошибок вида use-after-free (и не только):

let mut v: Vec<int> = vec![1, 2];let e = &v[0];v.push(3); // reallocates the vector, moving its contents // ! cannot borrow v as mutable because // ! it is also borrowed as immutable

let mut num = box 5i;let e = &*num;num = box 6i; // ! cannot assign to num because it is borrowed

let mut v = vec![1i, 2, 3];for &e in v.iter() { println!("{}", e); if e == 2 { v.push(-42); } // ! cannot borrow v as mutable}

43 / 70

Page 44: Rust: абстракции и безопасность, совершенно бесплатно

Borrowing and mutability

Отсутствие неожиданностей:

fn do_stuff(data: &mut BigData, should_process: || -> bool) { assert!(data.is_safe()); if should_process() { unsafely_handle_data(data); }}

44 / 70

Page 45: Rust: абстракции и безопасность, совершенно бесплатно

Borrowing and mutability

Наличие двух мутабельных ссылок позволяет реализоватьtransmute() (aka reinterpret_cast) в безопасном коде:

fn my_transmute<T: Clone, U>(value: T, other: U) -> U { let mut x = Left(other); let y = match x { Left(ref mut y) => y, Right(_) => panic!() }; x = Right(value); y.clone() }

45 / 70

Page 46: Rust: абстракции и безопасность, совершенно бесплатно

Lifetimes

«Наивное» заимствование может вызвать проблемы:

1. создаётся ресурс X;2. на ресурс X берётся ссылка a;3. ресурс X уничтожается;4. к [уничтоженному] ресурсу X осуществляется доступ через

ссылку a.

Use after free, доступ к закрытому файлу, etc.

Решение — статически обеспечить невозможность 4 перед 3.

46 / 70

Page 47: Rust: абстракции и безопасность, совершенно бесплатно

Lifetimes

С каждой ссылкой ассоциирован параметр — время жизнитого объекта, на который она указывает. Компиляторстатически проверяет, что каждая ссылка всегда «живёт»меньше, чем исходный объект:

fn make_ref<'a>() -> &'a int { let x = 10i; &x // ! x does not live long enough}

fn first_and_last<'a>(slice: &'a [T]) -> (&'a T, &'a T) { (&slice[0], &slice[slice.len()-1])}

fn first_and_last(slice: &[T]) -> (&T, &T) { // identical (&slice[0], &slice[slice.len()-1])}

47 / 70

Page 48: Rust: абстракции и безопасность, совершенно бесплатно

Lifetimes

Lifetime-параметры можно ассоциировать с областямивидимости:

let x;{ let n = 5i; x = &n; // ! n does not live long enough}println!("{}", *x);

48 / 70

Page 49: Rust: абстракции и безопасность, совершенно бесплатно

Lifetimes

Lifetime-параметры «заражают» типы:

struct AnIntReference<'a> { r: &'a int}

enum MaybeOwned<'a> { Owned(String), Slice(&'a str)}

49 / 70

Page 50: Rust: абстракции и безопасность, совершенно бесплатно

Lifetimes

Специальный идентификатор 'static обозначает время жизнивсей программы:

static ANSWER: int = 42;

fn print_static_int_only(r: &'static int) { // ' println!("{}", *r);}

fn main() { print_static_int_only(&ANSWER); // ok

let r = 21; print_static_int_only(&r); // ! r does not live long enough}

const MESSAGE: &'static str = "Hello world!";

50 / 70

Page 51: Rust: абстракции и безопасность, совершенно бесплатно

Shared ownership

В рамках одного потока — подсчёт ссылок:

use std::rc::Rc;{ let r = Rc::new(vec![1, 2, 3]); let r2 = r.clone(); println!("{}", *r); println!("{}", *r2);} // both references go out of scope, Vec is destroyed

51 / 70

Page 52: Rust: абстракции и безопасность, совершенно бесплатно

Многопоточность

52 / 70

Page 53: Rust: абстракции и безопасность, совершенно бесплатно

Потоки

Создаются функцией spawn():

spawn(move || { // unboxed closure println!("Hello from other thread!");});

Потоки — это потоки ОС.

Система типов гарантирует, что замыкание не захватит«опасные» переменные.

53 / 70

Page 54: Rust: абстракции и безопасность, совершенно бесплатно

Каналы

Общение между потоками происходит через каналы:

let (tx, rx) = channel();spawn(move || { tx.send(4u + 6); tx.send(5u + 7);});println!("{}, {}", rx.recv(), rx.recv());

54 / 70

Page 55: Rust: абстракции и безопасность, совершенно бесплатно

Shared state

Данные «без ссылок внутри» разделяемые с помощью Arc:

use std::sync::Arc;

let data = Arc::new(vec![1u, 2, 3]);

let for_thread = data.clone();spawn(move || { println!("From spawned thread: {}", *for_thread);});

println!("From main thread: {}", *data);

55 / 70

Page 56: Rust: абстракции и безопасность, совершенно бесплатно

Mutable shared state

За счёт системы типов использование синхронизацииобязательно. Таким образом, исключаются гонки данных(data races):

use std::sync::{Arc, Mutex};

let data = Arc::new(Mutex::new(vec![1u, 2, 3]));

let for_thread = data.clone();spawn(move || { let mut guard = for_thread.lock(); guard.push(4); println!("{}", *guard);});

let mut guard = data.lock();guard.push(5);println!("{}", *guard);

56 / 70

Page 57: Rust: абстракции и безопасность, совершенно бесплатно

Unsafe

57 / 70

Page 58: Rust: абстракции и безопасность, совершенно бесплатно

Что это такое

unsafe-блоки и unsafe-функции:

unsafe fn from_raw_buf<'a, T>(p: &'a *const T, n: uint) -> &'a [u8] { std::mem::transmute(std::raw::Slice { data: *p, len: n })}

fn fill_buffer<R: Reader>(r: R, size: uint) -> Vec<u8> { let v = Vec::with_capacity(size); unsafe { v.set_len(size) }; r.read(v.as_mut_slice()).unwrap(); v}

58 / 70

Page 59: Rust: абстракции и безопасность, совершенно бесплатно

Unsafe-операции

разыменование «сырого» указателя:

let n = 10i;let p = &n as *const int;println!("{}", unsafe { *p });

чтение/запись статической мутабельной переменной:

static mut COUNTER: u32 = 10;unsafe { COUNTER += 32 };println!("{}", unsafe { COUNTER });

вызов unsafe-функции:

extern { fn perror(); }unsafe { perror(); }

59 / 70

Page 60: Rust: абстракции и безопасность, совершенно бесплатно

Когда это нужно

ещё больше производительностиабстракциивзаимодействие с внешними библиотеками

Другими словами — очень редко!

60 / 70

Page 61: Rust: абстракции и безопасность, совершенно бесплатно

Инфраструктура

61 / 70

Page 62: Rust: абстракции и безопасность, совершенно бесплатно

Встроенные модульные тесты

#[test]fn test_something() { assert_eq!(true, true);}

#[bench]fn test_perf(b: &mut Bencher) { b.iter(|| { do_something(); });}

62 / 70

Page 63: Rust: абстракции и безопасность, совершенно бесплатно

Единица компиляции — crate

pub mod a { mod b { // ... } pub mod c { // ... }}

mod d { // ...}

На выходе — готовый бинарник (библиотека или executable)

63 / 70

Page 64: Rust: абстракции и безопасность, совершенно бесплатно

Менеджер сборки — Cargo

разработан Yehuda Katz — автором Bundlerсборка и управление проектом:

отслеживание зависимостейкомпиляция зависимостей, как на Rust, так и на Cкомпиляция проектазапуск тестов, модульных и интеграционныхгенерация пакетов и их деплой в репозиторий

reproducible builds

64 / 70

Page 65: Rust: абстракции и безопасность, совершенно бесплатно

crates.io — центральный репозиторий

Открылся совсем недавноПредназначен, в основном, для стабильных релизов400 пакетов спустя полторы неделиЯдро будущей экосистемы

65 / 70

Page 66: Rust: абстракции и безопасность, совершенно бесплатно

Проекты на Rust

66 / 70

Page 67: Rust: абстракции и безопасность, совершенно бесплатно

Servo — https://github.com/servo/исследовательский браузерный движокактивно развивается, уже проходит какие-то тесты~100000 строк

rustc — https://github.com/rust-lang/rustсам компилятор Rustсамый старый крупный проект~400000 строк

Cargo — https://github.com/rust-lang/cargoменеджер сборкиодин из наиболее новых проектов, idiomatic style~30000 строк

67 / 70

Page 68: Rust: абстракции и безопасность, совершенно бесплатно

Piston — https://github.com/PistonDevelopersколлекция проектов, связанных с разработкой игрбайндинги к OpenGL и другим графическим (и нетолько) библиотекамигровой движокGUI-библиотека

Zinc — https://zinc.rsARM-стекэффективный и безопасный фреймворк для RTOS-систем~17000 строк

Iron — https://ironframework.org/наиболее популярный веб-фреймворк (есть и другие!)middleware-basedвместе с HTTP-библиотекой Hyper ~8000 строк

68 / 70

Page 69: Rust: абстракции и безопасность, совершенно бесплатно

Ссылки

69 / 70

Page 70: Rust: абстракции и безопасность, совершенно бесплатно

Общееhttp://www.rust-lang.org/https://github.com/rust-langhttp://reddit.com/r/rusthttp://discuss.rust-lang.org/https://crates.io/irc.mozilla.org - #rust, #rust-internals, #cargo, #servo, ...https://groups.google.com/forum/#!forum/rust-russianhttp://blog.rust-lang.org/

http://habrahabr.ru/post/237199/http://habrahabr.ru/post/243315/

Документация и туториалыStackoverflow по тегу [rust]http://doc.rust-lang.org/guide.htmlhttps://github.com/rust-lang/rust/wiki/Docshttps://rustbyexample.com/

70 / 70