Комментарии 76
Не пытался садится за Rust всерьёз из-за синтаксиса. Он меня жутко пугает. Что посоветуете? Потерпеть сначала, а потом будет всё в порядке?
Не бойтесь ни грамма. Документация, в том числе русскоязычная — великолепна. Главное внимательно почитать и потренировать часть про времена жизни. Ну и если вы пришли из VM- или скриптового языка — различия стека и кучи.
Это Вы С++ во всей его красе наверное не видели
Мне тоже вначале было непривычно и местами неприятно, потом привык и перестал обращать внимание. Лично мне не нравится всеобщий сокращизм и стремление писать ключевые слова и идентификаторы в 2-3 символа. Другие наоборот фанатеют от этого.
Вообще, после того, как наешься радости production style C/C++… когда устанешь разгребать тонны кода от именитых компаний и брендов, который на поверку оказывается банальным индийским *, то начинаешь ценить в первую очередь не синтаксис, не абстрактную выразительность или там лаконичность языка, а то, какие проблемы он решает и какие гарантии он дает.
Rust решает фундаментальные проблемы с памятью и асинхронностью и одно это уже (для меня по крайней мере) перекрывает все его недостатки. Именно потому, что мифический индус даже при всем желании не сможет по незнанию или неосторожности заварить такую кашу, с которой мне обычно приходится разбираться.
Конечно, есть unsafe блоки, которыми можно устроить ад и в Rust, но их можно очень быстро отсмотреть. Можно даже настроить систему так, чтобы геррит/гитхаб разрешал ревьюить код, содержащий unsafe блоки только сениорам, тогда как safe Rust можно отдавать на ревью кому угодно.
Например, бот Rust Highfive выдает большое жирное предупреждение на pull request, который модифицирует unsafe код. Сразу дает понять, что тут могут быть серьезные баги и надо ревьюить особенно внимательно.
Спасибо за комментарий.
Предупреждаю — ниже взгляд человека, который НЕ разбирался в языке совершенно ни грамма.
Навскидку:
name: &'static str,
этот маленький '
крючёчек для меня, как человека с плохим зрением — просто сложно заметен.
Непривычно смотрится:
&self, f: &mut Formatter
но это просто нужно один раз понять (я не разбирался что всё это значит ещё. Догадываюсь, что, возможно, в Rust-е всё const-by-default, поэтому &mut
. А &
— потому что, так же, как и в плюсах, есть возможность передавать по ссылке/по значению. Но опять же — это просто догадки).
Непривычно смотрится просто знак восклицания println!
и всякие штуки, типа slice: &[i32]
.
Дальше:
// A tuple struct
struct Pair(i32, f32);
только с комментария догадываюсь, что это аналог алиаса (?): using Pair = std::tuple<i32, f32>;
и, возможно, доступ будет происходить по индексам.
Ну, а этот код из статьи — это вообще ад:
macro_rules! __impl_slice_eq1 {
($Lhs: ty, $Rhs: ty) => {
__impl_slice_eq1! { $Lhs, $Rhs, Sized }
};
($Lhs: ty, $Rhs: ty, $Bound: ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
#[inline]
fn eq(&self, other: &$Rhs) -> bool { self[..] == other[..] }
#[inline]
fn ne(&self, other: &$Rhs) -> bool { self[..] != other[..] }
}
}
}
Опять же — уверен, что если разобраться — всё становиться логичным.
Спасибо
этот маленький ' крючёчек для меня, как человека с плохим зрением — просто сложно заметен.Идентификаторы с, как вы его называете крючком, это лайфтаймы. В отличие от С++, где понятия времени жизни объекта и отношения владения не выражены в коде явно, в Rust это элемент синтаксиса.
Непривычно смотрится:
Когда в C++ вы принимаете аргументом конструктора и сохраняете в поле некую ссылку, вы неявно говорите «все взорвется, если конструируемый объект переживет тот, на который ссылается». Вам остается только надеяться что другие программисты не дураки и не передадут вам ссылку на временный объект.
В Rust такие отношения выражаются на лексическом уровне, поскольку каждая ссылка маркируется неким временем жизни, а компилятор статически проверяет, чтобы инварианты не нарушались. На самом деле в большинстве случаев, компилятор достаточно умный чтобы выводить лайфтаймы самостоятельно, поэтому их нужно писать только там, где вывод не работает.
Идентификаторы с крючком были введены, чтобы отличать их от других шаблонных параметров и чтобы их можно было аккуратно прилепить к ссылке:
fn my_function<'a, T>(reference: &'a T) -> &'a T;
Если вкратце — по умолчанию все параметры передаются по значению без копирования. То есть если вы передали что-то в другую функцию без &, больше вы его использовать не сможете. Это называется передача владения объектом. Передача же по ссылке производится явно, амперсандом (&). При этом владения объектом не происходит, и после возврата можно пользоваться им как обычно. Но одновременно можно заимствовать только неизменяемые ссылки, на которых нет в это же время изменяемой ссылки.
Как вы верно заметили, по умолчанию все ссылки и объекты неизменяемые. Изменяем ость нужно явно прописывать словом mut.
Знак восклицания после имени функции говорит о том, что это макрос. Вы ими пока голову не забывайте, есть темы поважнее.
Спасибо.
все параметры передаются по значению без копирования. То есть если вы передали что-то в другую функцию без &, больше вы его использовать не сможете.
По сути, в плюсах — это аналог rvalue с мув семантикой. Но в плюсах нет поддержки овнершипа на уровне языка/компилятора:
std::string str = "I'm the owner";
foo(std::move(str)); // передали овнершип в функцию
Как я уже писал Halt — смотрю Rust из-за этих манипуляций с лайфтаймом :)
1. Если у вас ссылочный только аргумент функции — вж можно не ставить, оно по умолчанию будет считаться из той области видимости, где функция вызывается. Касается как self, так и просто параметров.
fn do(arg: &Type) { ... }
2. Если у вас ссылочный только результат функции с self — вж тоже можно не писать, оно привязывается к вж self (кроме случаев, когда вж результата зависит от другого параметра, и вам надо это явно указать)
fn do(&self) -> &T { &self.member_of_type_t } //например
3. Ясное дело, что ссылку на созданный внутри функции объект возвращать нельзя — dangling pointer. Для такого есть Box — ссылка на объект в куче.
fn make_stack() -> &T { ... } //EPIC FAIL
fn make_heap() -> Box<T> { ... } //EPIC WIN
4. Не создавайте функции с нессылочным self без крайней необходимости — они уничтожают self (из правила, написанного мной выше)
fn kill_self(self) { ... }
5. Если у вас член структуры — ссылка, вы обязаны ее вж таскать с этой структурой везде. Логично, потому что если ссылающийся объект помрет без нашего ведома, мы получим segfault.
struct Container<'a> {
memb: &'a Item
}
только с комментария догадываюсь, что это аналог алиаса (?): using Pair = std::tuple<i32, f32>; и, возможно, доступ будет происходить по индексам.
Вот тут не угадали :) Кортежи в Rust есть и они пишутся просто скобками:
// Функция, возвращающая кортеж
fn get_tuple() -> (i32, f32) {
(42, 3.14)
}
// Деструктурирующее связывание:
let (x, y) = get_tuple();
// Можно и по индексам:
let t = get_tuple();
let x = get_tuple().0;
let x = t.1;
Структуры вида
struct Pair(i32, f32);
служат для другой цели. Их используют когда хочется связать несколько значений под одним общим именем типа, но отдельные поля именовать не хочется. Сюда можно отнести координаты, группы однотипных значений и т. д.Есть даже вырожденный паттерн, например
struct Meters(f32)
который может показаться бессмысленным, но на самом деле используется для повышения надежности программ.Ну, а этот код из статьи — это вообще ад:Дело в том, что это не простой код, это макрос. Идентификаторы с восклицательными знаками это тоже все макросы. Сделано специально так, чтобы их можно было отличить от обычных функций.
Такие конструкции можно сравнить с шаблонной магией в C++ которая очень мощная, но может быть довольно трудночитаема (загляните в boost или в stdlib).
Основная идея в том, чтобы упаковать весь ад внутрь абстракции, а наружу выставить вполне милый интерфейс, типа
vec![]
, который скрывает всю сложность, но дает удобство простому пользователю.Спасибо за объяснения.
Структуры вида struct Pair(i32, f32); служат для другой цели. Их используют когда хочется связать несколько значений под одним общим именем типа, но отдельные поля именовать не хочется.
По сути (очень грубо) это и есть тюплы. Просто это strong typedef (т.е., алиас, который кроме синонима вводит ещё и новый тип на основе которого можно делать перегрузку ф-й и прочее. То, чего не хватает плюсам на уровне языка).
struct Meters(f32)
— подтверждает это. На псевдо коде мы имеем что-то такого:
void foo(f32); // 1
void foo(Meters); // 2
foo(f32{0}); // 1
foo(Meters{0}); // 2
(Подправте, если ошибаюсь)
С макросами — понял — аналог шаблонов. Но тогда
Идентификаторы с крючком были введены, чтобы отличать их от других шаблонных параметров и чтобы их можно было аккуратно прилепить к ссылке:
есть и макросы (которые судя по комментариям ниже могут генерить код/модули) и есть шаблоны.
Спасибо за объяснения. Я фан явного указания жизни обьектов. Из-за вас теперь уже точно смотрю на Rust :)
Говорить что «макросы — аналог шаблонов» довольно странно, все равно как в контексте C++ говорить что, «#define — это аналог template».
Либо я вас не понял.
Ну, а этот код из статьи — это вообще ад:
Сорри.
(Это я писал.)
Конечно, есть unsafe блоки, которыми можно устроить ад и в Rust, но их можно очень быстро отсмотреть. Можно даже настроить систему так, чтобы геррит/гитхаб разрешал ревьюить код, содержащий unsafe блоки только сениорам, тогда как safe Rust можно отдавать на ревью кому угодно.
Например, бот Rust Highfive выдает большое жирное предупреждение на pull request, который модифицирует unsafe код. Сразу дает понять, что тут могут быть серьезные баги и надо ревьюить особенно внимательно.
Строго говоря, наличие unsafe в рамках модуля уже требует аккуратного review всего кода в модуле, в том числе safe, т. к. он тоже может нарушить инварианты, на которые полагается unsafe часть. Пример, вроде, был в Nomicon'е.
https://doc.rust-lang.org/nomicon/working-with-unsafe.html, там где рассматривается игрушечный Vec
.
Ну и вот это надо запомнить:
Unsafe code must trust some Safe code, but can't trust generic Safe code. It can't trust an arbitrary implementor of a trait or any function that was passed to it to be well-behaved in a way that safe code doesn't care about.
fn escape_str(wr: &mut fmt::Write, v: &str) -> EncodeResult
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
На это накладывается все еще непривычный синтаксис «имя: Тип», использование угловых скобок как для лайфтаймов, так и для «шаблонных» параметров.
Кстати, об угловых скобках. Относительно частая необходимость вложенных шаблонных параметров вызывает чисто читательский дискомфорт, ведь угловые скобки — на самом деле не скобки, большинство IDE не подсвечивает их правильно и чисто визуально они воспринимаются хуже, чем круглые или квадратные (а я-то гадал, почему в Scala дженерики используют квадратные скобки):
fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>>;
Имхо, не стоило из С++ брать угловые скобки для шаблонов и :: для неймспейсов, все равно ведь остальной синтаксис не очень похож, да и способ мышления все равно совсем другой нужен.
Но тут, видимо, уже ничего не поделаешь.
Синтаксис «имя: тип» я думаю выбран потому, что в отличие от C++ где аннотации типа обязательны, в Rust они являются скорее исключением и обязательны только в прототипах функций и структурах. В подавляющем большинстве случаев, типы внутри метода могут быть выведены полностью.
Помимо этого, аннотация типа через двоеточие активно применяется в научном сообществе особенно в работах по теориям типов и лямбда исчислению и в целом довольно интуитивна:
let x = 42;
let y: String = "hello_world".to_owned();
Делать же два разных синтаксиса объявления с аннотацией типа и без оной — еще хуже. Если делать по аналогии с C/C++
let x = 42;
String y = "hello_world".to_owned();
…то существенно усложняется парсинг, теряется читаемость и опять-таки появляется неоднозначность без особых преимуществ.
Синтаксис «имя: тип» я думаю выбран потому, что в отличие от C++ где аннотации типа обязательны, в Rust они являются скорее исключением и обязательны только в прототипах функций и структурах. В подавляющем большинстве случаев, типы внутри метода могут быть выведены полностью.
К этому моменту у меня претензий нет, когда изначально есть вывод типов через let (а не прикостыленное auto), это выглядит вполне органично.
А возвращаемое значение у функции через -> позволяет избавиться от безумного сишного синтаксиса указателей на функции. Это все понятно, просто непривычно.
Но вот угловые скобки вообще — это все-таки не очень.
Сравните:
Box<Map<Vec<i8>>>
Box[Map[Vec[i8]]]
Box(Map(Vec(i8)))
Для угловых скобок еще и шифт надо нажимать.
*
в зависимости от контекста может означать:- оператор умножения:
2 * 3
- указатель:
char*
- разадресацию указателя:
*pint = 42
- пользовательский
operator *
- наверняка, я еще что-то забыл, какие-нибудь триграфы
Компилятору C++ уже приходится разгребать завалы звездочек и применять шаблоны только чтобы построить AST.
Rust придерживается позиции разумного минимализма в отношении синтаксиса. С одной стороны, по возможности меньше сущностей, с другой — каждая сущность должна быть контекстно-свободной и означать только то, для чего создавалась.
Это упрощает парсер и облегчает чтение кода. Особенно это важно, поскольку на этапе обработки макросов уже должно быть известно, чему соответствует каждый идентификатор.
Квадратные скобки (не говоря уже о круглых) в Rust уже используются в синтаксисе слайсов и для индексирования, навешивать на них еще и роль шаблонов значит перегрузить синтаксис.
Надо сказать, что разработчики довольно много времени уделяют вопросам так что с большой вероятностью то, что вы сейчас видите — это действительно оптимальный вариант. Например, по поводу синтаксиса для лайфтаймов в свое время было очень много споров, но никто в итоге так и не смог предложить лучшего варианта с учетом всех «за» и «против».
Легко рассуждать об отдельном элементе синтаксиса, забывая обо всей остальной кухне.
Но я согласен, моей квалификации недостаточно, чтобы предложить более удачный вариант с учетом всего синтаксиса в целом.
плюс ещё update: a(1) = "xxx"
эквивалентно a.update(1, "xxx")
Любой метод с &self можно вызывать напрямую как обычную функцию, принимающую первым параметром объект:
struct Foo(u32);
impl Foo {
pub fn bar(&self, arg: u32) -> u32 { self.0 + arg }
}
fn main() {
let foo = Foo(42);
assert_eq!(Foo::bar(&foo, 1), 43);
}
То что упомянул Optik и про что написал я к ufcs особого отношения не имеет.
Разговор про синтаксический сахар, который позволяет делать read-/update-like методы. Это несколько похоже на operator()
в плюсах (для read варианта). Т.е. self
/this
по-прежнему передается неявно (в отличии от того, что разрешает ufcs).
Т.е. a(x, y)
как rvalue означает (эквивалентно) a.apply(x, y)
, а a(x, y) = z
=== a.update(x, y, z)
, IIRC
Например,
a + b
можно вызвать и как a.add(b)
.Это ближе, да. Только в случае скалы нет прибитого гвоздем количества аргументов, как если аналогичную вещь в расте реализовать через новый trait в std::ops.
Scala в смысле гибкости синтаксиса прекрасна. И, порой, ровно поэтому же ужасна: придумает кто-нибудь в очередной библиотеке оператор «гибкий кораблик» a <=≈=> b
, и думай после этого где его искать и как по него гуглить (по мотивам реальной истории про аналогичный оператор).
С другой стороны, если IDE может нормально прожевать весь синтаксис и подсветить оператор именно в контексте текущего использования (как делает KDevelop для C++), то пожалуйста, лишь бы это было оправдано.
Пока шел домой понял, что пример со звездочками не очень, ибо Rust-у, в общем-то, приходится делать то же самое. Гораздо показательнее в отношении C++ такой пример:
Где-то в тексте программы есть конструкция
(a)(b)
где a
и b
— некие идентификаторы. Надо выписать все возможные конструкции, которые могут за этим скрываться. Вот тут уже без знания фактических типов
a
и b
ничего распарсить не получится.Где-то в тексте программы есть конструкция (a)(b) где a и b — некие идентификаторы. Надо выписать все возможные конструкции, которые могут за этим скрываться.Расскажите тем, кто шапочно знаком с C++, что там может скрываться.
В C здесь может скрываться
- Приведение типа b к a. В C++ тоже есть.
- Вызов функции (я даже как‐то писал
(cond ? func1 : func2)(args)
) по указателю на функцию. В C++ вроде тоже должно быть. - Только C++: вызов оператора вызова функции у
b
. - Объявление функции. Компилятор по‐умолчанию подставляет
int
как возвращаемый тип, но если на контекст ограничений нет, то можно увидетьrettype (funcname)(argtype)
и без нестандартного поведения компилятора. - Вроде в C++ это может быть частью объявления с инициализацией.
В общем, три варианта только в C, и я ещё не уверен, что перечислил все. Кстати, если на контекст ограничений совсем нет, то ещё есть варианты «это часть строкового литерала», «это часть комментария» и «это то же, что и (b)
, потому что MACRO(a)
раскрывается в пустоту».
- Часть объявления переменной (да, так можно и в C):
(int)(x);
- Часть более длинной цепочки приведения
(a)(b) …c
Вызов операторауже сказали()
у объектаa
с параметромb
- Цепочка вызовов оператора
()
:foo(a)(b)(c)
- Вызов функции-члена через указатель на нее, не то же самое, что просто через указатель на функцию
- Наверняка еще что-то забыл
MyClass(a)(b)
.- Конструктор через вызов placement new, завернутый в макрос
- Вызов любых операторов через синтаксис x.operator Y()
А вы попробуйте добавить в синтаксис лиспа аннотации типов :)
У Racket есть типизированный диалект, выглядит вот так:
(define (foo [a : Number] [b : Number]) : Number
(let ([c : Number (+ a b)])
(* 2 c)))
(define (bar (a : Number) (b : Number)) : Number
(let ((c : Number (+ a b)))
(* 2 c)))
Правда квадратные скобки можно заменить круглыми, язык требует только чтобы открывающая и закрывающая скобки были одинаковыми, но принято всё-таки разбавлять и как по мне, читабельности оно действительно добавляет.
P.S. Вывод типов (для let
, например) тоже есть.
Мне кажется или вы подтвердили мое предположение? :^)
Я с ним и не спорил. (:
Даже в не типизированном или, вернее, динамически типизированном варианте языка используются квадратные скобки. Правда сам на ракете не пишу, просто изучал из интереса, но кажется, что читаемость это заметно повышает. Есть ещё практика раскрашивать (в IDE) скобки в разные цвета, может тоже помогает, если приноровиться, не могу судить.
Насчёт префиксной формы не совсем понял, речь о следующем?
(: foo (Number Number -> Number))
(define (foo a b)
(let ([c (+ a b)])
(* 2 c)))
Могу ошибаться, но сделано оно скорее для упрощения добавления типов в имеющийся код и, кажется, работает не везде. Например, разве можно такую форму с let
использовать?
Мне кажется, что все-таки проблемы индейцев шерифа волновать не должны. В том смысле, что подсветка синтаксиса языка — это обязанность редактора.
Компилятор предоставит LSP поддержав который, редактор или IDE получат всю необходимую информацию. А уж подсветить и обрабатывать угловые скобки в шаблонах как парные символы — дело техники.
Про хаскель в курсе, опять же, кажется, что там нередко принято проставлять типы только в нужных местах. Мне всё-таки больше по вкусу подход раста, где для функций их указывать обязательно. Ну и мне как-то больше по душе когда типы идут вместе с функцией, а не отдельно.
Насчёт скобочек в лиспе — вроде как "тру лисперы" такое порицают, да и (наверное) не зря автоформатирование расставляет их не как в других языках. Ну и когда я лисп щупал, то хотелось побольше "проникнуться", так что подстраивался под местные обычаи. (:
Если честно, я тоже не понимаю, зачем тасовать данные туда-сюда через строки и почему нельзя было сразу сделать вменяемый интерфейс
Вменяемый и стабильный интерфейс это дело долгое с большим количеством неразрешенных вопросов, это дело если не всего этого года то следующего. А serde и diesel на стабильном Rust должны были работать еще вчера. Поэтому пока сделали ровно необходимый минимум.
Cистема сборки компилятора и стандартной библиотеки Rust была переписана на сам Rust с использованием Cargo
Ууу, rustbuild, сраное говно.
Вместо того, чтобы вести себя как приличные системы сборки и работать с графом зависимостей с таргетами в узлах и командами привязанными к таргетам, это наколеночное поделие херачит большую часть билда и тесты подряд в императивном стиле, режет параллелизм, добавляет зависимости. Когда совсем приспичивает приходится сравнивать timestamp'ы вручную (!) кодом на Rust.
Как же его хочется переписать, но нет возможности.
Хотя читается, конечно на порядок лучше старых мейкфайлов.
Поэтому пока сделали ровно необходимый минимум.По поводу API я так и предполагал. Я так понимаю, в будущем будет возможность конвертации между `quote::Tokens` и `TokenStream`, или же оно вообще будет приведено к одному типу? Ну или через From/Into/AsRef.
Ууу, rustbuild, сраное говно.А можно подробнее?
По поводу API я так и предполагал. Я так понимаю, в будущем будет возможность конвертации междуquote::Tokens
иTokenStream
, или же оно вообще будет приведено к одному типу? Ну или через From/Into/AsRef.
Я конкретно за этим подробно не слежу, но про предварительные планы можно почитать тут и тут.
Что куриличем руководствовались разработчики, почему было сделано именно так?
(a) leverage Cargo as much as possible and failing that (b) leverage Rust as much as possible!
Вообще, я так понимаю, можно ответить вашими же словами, про то что сделали чтобы было, а потом это все будет допиливаться.
Да, разумеется, функционально оно работает, компилятор и библиотеку собирает и тестирует, можно дальше улучшать. Новые фичи добавляются на порядок легче по сравнению с мейкфайлами.
То что дизайн некошерный, это вопрос ортогональный. Меня в основном беспокоит то, что для контрибьюторов, которые хотят собирать и тестировать локально, rustbuild хуже чем старая система.
Есть ли конкретные обрисованные планы развития?
Важная инфраструктура (производство релизных сборок, расширение тестирования для разных платформ) будет расширяться, в остальном расчет на то что сторонние контрибьюторы будут подчищать конюшни.
Одна из целей переписывания системы сборки было как раз привлечение новых контрибьюторов.
В CONTRIBUTING.md достаточно подробно всё описано (в том числе как искать entry-level тикеты).
Для начала рекомендую найти какую-нибодь опечатку или функцию с плохой документацией, исправить и сдалать pull request на гитхабе просто чтобы опробовать процесс. Патчей такого рода много, ревьюеры доброжелательные и если что-то не так всегда подскажут, поправят + ревью и мердж достаточно оперативно происходят, не надо ждать месяц пока maintainer соизволит взглянуть на патч, как в некоторых проектах.
1. Почему у макросов нет пространства имен? Это же неудобно, начиная с того, что непонятно из какого пакета он тянется, и заканчивая конфликтами имен из разных библиотек. Почему не сделали так? (мне кажется это логичнее)
let v = std::vec![1, 2, 3];
2. Зачем нужно отдельно указывать extern_crate, почему просто не писать
use derive_new::new;
И если нет такого локального модуля, то воспринимать его как crate derive_new и качать зависимость.
Может есть этому разумные обьяснения, кто знает?
В кратце — можно и нужно проще, но текущая ситуация хорошо отражает что происходит в действительности под капотом и после осознания сильно не напрягает.
можно и нужно проще
Про "нужно" не особо однозначно, а реддите хорошое обуждение у статьи было:
https://www.reddit.com/r/rust/comments/5m4w95/the_rust_module_system_is_too_confusing/
Насколько я понимаю, у макросов нет пространства имен потому что они работают до их разрешения и сами могут генерировать новые модули в процессе работы.
Те макросы, которые есть сейчас (macro_rules!
) это в некотором смысле временная мера, связанная с тем, что в 1.0 должны были быть макросы, но привести их в идеальное состояние не было времени.
Сейчас вместе с процедурными макросами, описанными в статье, делаются макросы by-example 2.0, у которых будет и собственное пространство имён, и модулярность, и разрешение имён совмещённое вместе с разворачиванием макросов в один этап.
Это тоже дело долгое, но в roadmap'е назначено на этот год.
Если просто как одно из средств разработки то да, можно. Базовые возможности языка стабилизированы начиная с версии 1.0. Этим гарантируется последующая обратная совместимость и что API внезапно не поменяется.
Есть много компаний, которые используют Rust в разработке, в то же время надо понимать, что каждый использует язык по своему.
Для полноценного повседневного использования не хватает как минимум поддержки в IDE (которая вот-вот должна выйти из альфы) и развитой экосистемы библиотек.
Если говорить про веб, то лучше всего на этот вопрос ответит сайт arewewebyet.org.
Есть, но там с отображением некоторых "встроенных" типов (Option, Result) было похуже, см. https://michaelwoerister.github.io/2015/03/27/rust-xxdb.html, но ситуация могла изменится, смотрел в середине 2016 года.
Черная магия метапрограммирования: как работают макросы в Rust 1.15