А можно конкретнее? Я сравнил память из кучи и на стеке с точки зрения её управления в Rust. Может, если я плохо выразился, попробуйте Вы объяснить лучше.
Я рад, что мне удалось привлечь Ваше внимание к языку. Это и было целью статьи. О чём она? О том, какое место Rust занимает в ряду существующих языков, чем может похвастаться, чем уникален (собственно, "зачем"), какие проблемы ожидают новичков, плюс некоторая общая информация о языке и сообществе. Вопрос, на который она не отвечает, так это "как": как Rust удаётся гарантировать безопасность, при этом не теряя скорости (а где-то и прибавляя — это отдельная история).
«Маркетинговые высказывания» — это лишь первое предложение, которое есть перевод определения на заглавной странице самого языка. Возможно, вы найдёте что-то похожее в Википедии, но вот оригинальный материал, который следует за определением, — нет.
Напоследок, про «рекламу себя любимого». Было бы крайне неубедительно призывать кого-то изучать Rust, вливаться в сообщество, да при этом самому оставаться в стороне.
Хорошо же на Хабре работает саморегуляция! Зачем пыхтеть, думать, писать материал, получив +51 к посту, если можно вот так зайти, написать первым «статья не о чём» (не удосужившись понять, о чём она) и получить +42. А Ваши статьи о чём?
Можно перевести иначе. «отображение» — это слишком общий, да к тому же перегруженный математикой термин. Давайте представим, что нам нужно перевести выражение:
input.map(|x| x^2)
По-русски это звучит как «каждому элементу x из входной последовательности сопоставляетсяx^2». Отсюда, собственно, и термин "сопоставление". Он не ассоциируется с математикой и лучше отражает смысл происходящего.
Простите, но «трейт» уж совсем никак не звучит по-русски. «Типаж» звучит нитересно, но «способность» лучше вписывается в полные фразы:
«тип реализует способность» vs " тип реализует типаж" vs «тип реалиует трейт»
Справедливости ради стоит отметить, что большая часть кода, который оперирует с массивами, использует разрезы (slice), для которых индексация работает и всегда работала. Только непосредственные владельцы векторов (Vec) вынуждены столкнуться с временным неудобством индексирования. А со всем остальным согласен ;)
Далее про RAII и «детский лепет».
Указатель на динамическую панять (Box) тоже живёт, пока живёт его владелец. Получив ссылку на содержимое, мы «замораживаем» указатель на время действия ссылки (определяется статически, так что за это не платим). Rust не позволит нам угробить динамическую память, пока на неё ссылаются (так же, как и в приведённом примере с вектором).
Сборщик мусора в Rust есть, но он сугубо по желанию (не один рубильник для всего сразу, а Gc просто как тип указателя, реализованный как сторонняя библиотека). Так что системное ПО живёт счастливо и прелестями Gc не пользуется.
Ну и опять же, no offense, но просто все эти вещи должны быть раскрыты в основной статье, а не глубоко в каментах.
Я раскрыл общие черты языка, без особой конкретики, да в весьма субъективном соусе. Такого рода пост, по Вашему, неполноценен? Понимаю, что Вы хотите большего, и постараюсь осветить, но только как приятное дополнение, а не требование.
Давайте разберём те самые «голословные» утверждения:
1. Когда-нибудь слышали о Option (в Scala) или Maybe (в Haskell)? Вот пример реализации дерева на Rust, и никаких unsafe{} блоков не нужно.
2. В плюсах ссылка есть лишь синтаксический сахар к указателю. Компилятор не гарантирует её доступность:
int *x = 123;
int &y = *x;
y = 1; // memory access violation
Далее по Вашим примерам. a) В Rust не нужно вручную удалять память (это ведь источник ошибок), и переменные живут до конца своей области видимости. Но мы можем немного изменить пример, не меняя сущности:
let mut array = Vec::new();
array.push(1);
let ptr = array.get(0); // возвращает ссылку на первый элемент
array.push(2); // небезопасно, ибо память под вектор может измениться
Получаем справедливое ругательство о том, что мы не имеем право изменять массив, пока жива ссылка на один из его элементов:
:21:9: 21:14 error: cannot borrow `array` as mutable because it is also borrowed as immutable
:21 array.push(2);
^~~~~
:20:19: 20:24 note: previous borrow of `array` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `array` until the borrow ends
:20 let ptr = array.get(0);
^~~~~
:22:6: 22:6 note: previous borrow ends here
:17 {
:18 let mut array = Vec::new();
:19 array.push(1);
:20 let ptr = array.get(0);
:21 array.push(2);
:22 }
б) Как я уже сказал, в обычном коде Rust нет указателей, а ссылки всегда действующие, так что перевести Ваш пример на Rust не представляется возможным в пределах безопасного кода.
Я понимаю Ваше возмущение, но Вы не сможете познать Rust, оперируя исключительно моделью программирования С/C++. Для того, чтобы получить помощь от компилятора в виде гарантии безопасности Ваших операций с памятью, нужно думать немного иначе, и изучение функционального программирования в целом очень тому помогает.
Если будет возможность, посмотрите вот это выступление одного из разработчиков языка, либо хотя бы слайды от него.
Разработчики языка просто хотят, чтобы конфигурация по-умолчанию была как можно проще, и поведение было предсказуемее. При этом переключить её в режим лёгких потоков не составляет труда, не требует переписывания потокового кода. О чём это маякует? О том, что разработчики молодцы и учитывают все требования сообщества.
Крайности. Виртуальные функции как-раз несут реальную пользу, в отличие от перегрузки. Так что вносимое усложнение языка обосновано. Более того, в Rust нет наследования, поэтому определить, какая функция будет вызвана в конкретном месте, намного проще — достаточно посмотреть, какое (или какие) из реализованных (и доступных области видимости) способностей (traits) эту функцию имеют.
Rust не остановится на клиенте. Да, на сегодняшний день Go обладает значительно более сильной инфраструктурой для серверной части.
Однако, допустим, на Rust вырастет неплохой http-server (teepee). У разработчиков появится возможность использовать Rust везде — и на сервере, и на клиенте, даже в Javascript. Зачем тогда компаниям будет нанимать разных специалистов на Go и Rust, держать изолированные кодовые базы, если можно всё писать на Rust, используя общие куски кода и там, и сям?
Более того с последним релизом Rust перешел на OS threads, против собственных легковесных green threads по умолчанию, что делает серверное программирование затруднительней.
Легковесные потоки никуда не делись, они включаются одной строчкой. Неужели это так затруднительно? :)
Я работаю с С++ по профессии уже как минимум 7 лет, но таким суровым ещё не стал. Видимо, нужно программировать ещё больше, не отвлекаясь на другие языки в свободное время ;)
А если серьёзно, то постараюсь сравнить подробнее и с примерами в следующей статье, раз уж ввязался (на свою голову)… Жаль только, с С++ 11 опыта у меня нет, так что сравнение может получиться нечестным.
Понятно. Кажется, мы пришли к банальному обсуждению революционного развития против эволюционного. Rust не вызывал бы такую бурю эмоций (смотрите соотношение up/down в посте и комментариях), если бы не предлагал чего-то координально нового (безопасность + низкоуровневость) ;)
В ссылке, что я дал для Ubuntu, есть deb пакеты. Как я понимаю, можно либо подключить себе этот репозиторий и обновляться стандартными средствами, либо качать напрямую.
Rc
иGc
содержит небезопасный код для управления памятью. В области безопасного кода операции «удаления» нет, именно это имелось ввиду.«Маркетинговые высказывания» — это лишь первое предложение, которое есть перевод определения на заглавной странице самого языка. Возможно, вы найдёте что-то похожее в Википедии, но вот оригинальный материал, который следует за определением, — нет.
Напоследок, про «рекламу себя любимого». Было бы крайне неубедительно призывать кого-то изучать Rust, вливаться в сообщество, да при этом самому оставаться в стороне.
«тип реализует способность» vs " тип реализует типаж" vs «тип реалиует трейт»
Просветите меня, как по-русски грамотно перевести trait?
Очень даже бесплатная. По крайней мере Option<&T> под капотом использует всё тот же NULL. Проверяется просто:
Далее про RAII и «детский лепет».
Указатель на динамическую панять (Box) тоже живёт, пока живёт его владелец. Получив ссылку на содержимое, мы «замораживаем» указатель на время действия ссылки (определяется статически, так что за это не платим). Rust не позволит нам угробить динамическую память, пока на неё ссылаются (так же, как и в приведённом примере с вектором).
Сборщик мусора в Rust есть, но он сугубо по желанию (не один рубильник для всего сразу, а Gc просто как тип указателя, реализованный как сторонняя библиотека). Так что системное ПО живёт счастливо и прелестями Gc не пользуется.
Я раскрыл общие черты языка, без особой конкретики, да в весьма субъективном соусе. Такого рода пост, по Вашему, неполноценен? Понимаю, что Вы хотите большего, и постараюсь осветить, но только как приятное дополнение, а не требование.
1. Когда-нибудь слышали о Option (в Scala) или Maybe (в Haskell)? Вот пример реализации дерева на Rust, и никаких unsafe{} блоков не нужно.
2. В плюсах ссылка есть лишь синтаксический сахар к указателю. Компилятор не гарантирует её доступность:
Далее по Вашим примерам.
a) В Rust не нужно вручную удалять память (это ведь источник ошибок), и переменные живут до конца своей области видимости. Но мы можем немного изменить пример, не меняя сущности:
Получаем справедливое ругательство о том, что мы не имеем право изменять массив, пока жива ссылка на один из его элементов:
:21:9: 21:14 error: cannot borrow `array` as mutable because it is also borrowed as immutable
:21 array.push(2);
^~~~~
:20:19: 20:24 note: previous borrow of `array` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `array` until the borrow ends
:20 let ptr = array.get(0);
^~~~~
:22:6: 22:6 note: previous borrow ends here
:17 {
:18 let mut array = Vec::new();
:19 array.push(1);
:20 let ptr = array.get(0);
:21 array.push(2);
:22 }
б) Как я уже сказал, в обычном коде Rust нет указателей, а ссылки всегда действующие, так что перевести Ваш пример на Rust не представляется возможным в пределах безопасного кода.
Я понимаю Ваше возмущение, но Вы не сможете познать Rust, оперируя исключительно моделью программирования С/C++. Для того, чтобы получить помощь от компилятора в виде гарантии безопасности Ваших операций с памятью, нужно думать немного иначе, и изучение функционального программирования в целом очень тому помогает.
Если будет возможность, посмотрите вот это выступление одного из разработчиков языка, либо хотя бы слайды от него.
Однако, допустим, на Rust вырастет неплохой http-server (teepee). У разработчиков появится возможность использовать Rust везде — и на сервере, и на клиенте, даже в Javascript. Зачем тогда компаниям будет нанимать разных специалистов на Go и Rust, держать изолированные кодовые базы, если можно всё писать на Rust, используя общие куски кода и там, и сям?
Легковесные потоки никуда не делись, они включаются одной строчкой. Неужели это так затруднительно? :)
А если серьёзно, то постараюсь сравнить подробнее и с примерами в следующей статье, раз уж ввязался (на свою голову)… Жаль только, с С++ 11 опыта у меня нет, так что сравнение может получиться нечестным.
pcwalton.github.io/blog/2013/04/18/performance-of-sequential-rust-programs/
Были и другие, сейчас затрудняюсь найти…
Mozilla делает его для себя. Они считают, что если язык позволит создать Servo, то он годен и для других задач сообщества.
Цифры какие-то наверняка есть, ведь Servo не вчера появился. Будет интересно взглянуть на них, когда разработчики сделают post-mortem.
Тут не поспоришь. Проще вообще ничего нового не придумывать.
На этот счёт я спокоен, ибо сообщество у Rust завидное ;)