LINUX.ORG.RU

Вышел Rust 1.8

 


3

7

Команда Rust с удовольствием сообщает о выходе новой стабильной версии Rust 1.8. Rust — это язык системного программирования, фокусирующийся на безопасности, скорости и поддержке многопоточного программирования.

Как обычно, вы можете установить Rust 1.8 с соответствующей страницы на нашем сайте и посмотреть подробные примечания к выпуску 1.8 на GitHub'е. В этом релизе было принято около 1400 патчей.

Что нового в стабильной версии 1.8

Этот выпуск содержит два нововведения, и приятный сюрприз для пользователей Windows! Помимо этого идёт работа по замене системы сборки Rust, основанной на make, на Cargo.

Первое нововведение – это возможность перегрузки составных операторов присваивания, таких как += и -=. Изменение было принято в RFC 953 и выглядит следующим образом:

use std::ops::AddAssign;

#[derive(Debug)]
struct Count { 
    value: i32,
}

impl AddAssign for Count {
    fn add_assign(&mut self, other: Count) {
        self.value += other.value;
    }
}   

fn main() {
    let mut c1 = Count { value: 1 };
    let c2 = Count { value: 5 };
    c1 += c2;
    println!("{:?}", c1);
}

Эта программа выведет Count { value: 6 }. Как и в других трейтах, перегружающих операторы, ассоциированный тип позволяет использовать разные типы в левой и правой части оператора (см. RFC 953).

Второе нововведение, взятое из RFC 218, не такое значительное. В предыдущих версиях Rust структура, не содержащая полей, должна была объявляться без фигурных скобок:

struct Foo; // works
struct Bar { } // error

Вторая форма объявления больше не является ошибочной. Изначально эта форма была запрещена из соображений согласованности с другими пустыми объявлениями, а также для предотвращения неоднозначности синтаксического разбора. Но эта неоднозначность была устранена, начиная с Rust 1.0. Кроме того, запрет этой формы создавал трудности при написании макросов, требуя специальной обработки. Наконец, пользователям, ведущим активную разработку, иногда требовалось менять пустую структуру на непустую и наоборот, что требовало лишней работы и приводило к некрасивым diff'ам.

Возвращаясь к Windows — теперь 32-х битные MSVC сборки поддерживают размотку стека, что переводит платформу i686-pc-windows-msvc в класс 1 (о классах поддержки платформ).

Мы с давних пор используем make для сборки Rust'а, но у нас уже есть своё замечательное средство сборки для программ на Rust: Cargo. В Rust 1.8 мы добавили предварительную поддержку новой системы сборки, написанной на Rust и основанной на Cargo. Мы ещё не используем её по умолчанию, и она требует значительной доработки, поэтому подробное её описание появится в примечаниях к выпуску после её завершения. Сейчас вы можете посмотреть подробности по ссылке на PR 31123.

Стабилизация библиотек

В Rust 1.8 около 20 функций и методов было переведено в категорию стабильных. Их можно разбить на три группы: работа со строками в кодировке UTF-16, различные API для работы со временем, и дополнительные трейты, необходимые для перегрузки операторов, упомянутые в секции об изменениях в языке.

Нововведения в Cargo

  • cargo init создаёт проект в текущем каталоге, не создавая новый, как делает cargo new
  • cargo metadata - дополнительная субкоманда для получения метаданных
  • .cargo/config теперь допускает ключи -v и --color
  • Улучшены возможности Cargo по поддержке платформоспецифичных зависимостей.

Подробное описание изменений.

>>> Вышел Rust 1.8

★★★

Проверено: maxcom ()
Последнее исправление: shahid (всего исправлений: 5)

Ответ на: комментарий от Kuzy

Почему я уже две страницы читаю

Потому что у тебя короткие страницы. Вот у меня срач о синтаксисе закончился еще на первой.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Спасибо, пофиксил. Вот теперь торт.

Kuzy ★★★
()
Ответ на: комментарий от Kuzy

Почему я уже две страницы читаю, как примерно адекватные люди спорят про синтаксис?
Он же никак не влияет на разработку, когда используешь язык больше недели.

cat "test... test... test..." | perl -e '$??s:;s:s;;$?::s;;=]=>%-{<-|}<&|`{;;y; -/:-@[-`{-};`-{/" -;;s;;$_;see'

anonymous
()
Ответ на: комментарий от qnikst

Ну, таки модель CSP появилась после Паскаля. Да и вообще - не будем судить по недоязычкам :)

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

И еще насчет сложности: http://smallcultfollowing.com/babysteps/blog/2015/12/18/rayon-data-parallelis... Для D такое есть?

Есть давно уже, года с 2011, кажется: http://dlang.org/phobos/std_parallelism.html

Дело в том, что memory safety - это ЧАСТЬ ПРИКЛАДНОЙ ЗАДАЧИ (именно так, капсом).

Это зависит от того, как сформулировать. В моих прикладных задачах слишком много высокоуровневых абстракций, чтобы я мог позволить себе думать о сохранности памяти и при этом рассчитывать решить их за вменяемое время.

А на мой, идея добавить туда контроль за памятью кажется блестящей и назревшей (и я профессионально пишу на Си). И кстати, по сравнению с убожеством, которое называт «чистым Си», в Rust есть еще много чего.

Хорошо, дело ваше. Наверное, это правильно, хотя и не просто.

Развитие языков программирования должно было остановиться на Паскале?

Нет, конечно. Но только иногда нет смысла изобретать новые велосипеды, если уже два есть. Хотя ребята старались сделать как лучше. А уж что получилось, то получилось.

Vudod ★★★★★
()
Последнее исправление: Vudod (всего исправлений: 1)
Ответ на: комментарий от Vudod

Есть давно уже, года с 2011, кажется: http://dlang.org/phobos/std_parallelism.html

Как и ожидалось - без всякой проверки на алиасинг. См. второй абзац Data-race freedom в статье.

Дело в том, что memory safety - это ЧАСТЬ ПРИКЛАДНОЙ ЗАДАЧИ (именно так, капсом).

Это зависит от того, как сформулировать.

Не зависит. Совсем. Потому что при порче памяти ты тупо получаешь некорректные результаты.

В моих прикладных задачах слишком много высокоуровневых абстракций, чтобы я мог позволить себе думать о сохранности памяти и при этом рассчитывать решить их за вменяемое время.

А еще твои задачи позволяют тебе разменять «недумание о сохранности» на оверхед сборки мусора. Но Rust делался в первую очередь для задач, где такой размен невозможен, а во вторую - для повышения порога, за которым такой размен выгоден.

Но только иногда нет смысла изобретать новые велосипеды, если уже два есть.

О каких велосипедах речь? До Rust уже были не-экспериментальные языки, которые обеспечивали memory safety без GC?

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от Vudod

В моих прикладных задачах слишком много высокоуровневых абстракций, чтобы я мог позволить себе думать о сохранности памяти и при этом рассчитывать решить их за вменяемое время.

Не понятно. Главное, чтобы с сегфолтом не падало, а если часть массива левыми значениями перепишется это нормально?

red75prim ★★★
() автор топика
Ответ на: комментарий от red75prim

Смысл в том, что о сохранности памяти должны в первую очередь беспокоиться автоматические механизмы.

Vudod ★★★★★
()
Ответ на: комментарий от Vudod

Я не пойму, тебя заставляют писать на растишке вместо твой любимый язык? Сабж - язык для СИСТЕМНОГО ПРОГРАММИРОВАНИЯ и прочих областей, где gc неуместен. Не подходит - не юзай, ёпт.

anonymous
()
Ответ на: комментарий от anonymous

Именно для системного программирования он и не годится. Если бы не позиционировался именно так и так агрессивно не продвигался бы адептами, то возражений бы не было.

northerner ★★★
()
Ответ на: комментарий от northerner

Именно для системного программирования он и не годится.

Сказал, как в лужу пёрднул.

anonymous
()
Ответ на: комментарий от Vudod

Потому что каждый раз нужно думать, что написать: a, mut a, &a, &mut a?

Дык, думать и так придётся, если язык разрешает выбирать между копированием, передачей владения и передачей по ссылке. Причём выбор, как по мне, диктуется логикой происходящего, а не правилами языка.

В языках с GC принято «неявно» передавать по ссылке, что свои нюансы несёт. Например, вообще невозможность навесить константность на параметр-ссылку.

И в D тоже имеются константные ссылки/указатели, да ещё и иммутабельные в придачу.

DarkEld3r ★★★★★
()
Ответ на: комментарий от arcanis

В первую очередь фича для макрописателей, чтоб ставить скобки не глядя, будут ли там поля.

anonymous
()
Ответ на: комментарий от tailgunner

И без &mut всё еще не получилось.

Я не понял, вас смущает, что функция, меняющая нечто принимает ссылку на не-конст нечто? Что для вас трагично? Константность по-умолчанию? Передача по значению по умолчанию?

anonymous
()
Ответ на: комментарий от red75prim

Неудобно без редактирования ): . >&mut v[0..10] *= 2;,кстати, и не компилируется.

Так написали же, если реализовать для массива специальный интерфейс. Кстати, раст позволяет реализовывать интерфейсы для чужих, в том числе и встроенных типов, поэтому если вам нужно умножать векторы на скаляр, вы можете добавить эту фичу прямо у себя в проекте.

anonymous
()
Ответ на: комментарий от Vudod

Смысл в том, что о сохранности памяти должны в первую очередь беспокоиться автоматические механизмы.

Золотые слова. В расте есть автоматический механизм, заботящийся о сохранности памяти, причём ещё на этапе компиляции. А вот в языках со сборкой мусора такого механизму, увы, нет. Ну, если не считать контроль выхода за границы массива и неудаление того, что может ещё понадобиться, но этого недостаточно.

anonymous
()
Ответ на: комментарий от Vudod

Можно было и просто написать: для моего проекта плюсы языка со сборкой мусора перевешивают минусы. Генератор Rust обёрток над COM-интерфейсами я тоже на F# писал.

red75prim ★★★
() автор топика
Ответ на: комментарий от anonymous

&mut v[0..10] *= 2;,кстати, и не компилируется

Так написали же, если реализовать для массива специальный интерфейс. Кстати, раст позволяет реализовывать интерфейсы для чужих, в том числе и встроенных типов, поэтому если вам нужно умножать векторы на скаляр, вы можете добавить эту фичу прямо у себя в проекте.

Это я знаю. И работающий пример приводил: http://is.gd/A5kE8J

Но почему-то взбрело в голову, что для такой операции слева нужно явно взять &mut.

red75prim ★★★
() автор топика
Ответ на: комментарий от northerner

Именно для системного программирования он и не годится.

Почему?

theNamelessOne ★★★★★
()
Ответ на: комментарий от Vudod

Смысл в том, что о сохранности памяти должны в первую очередь беспокоиться автоматические механизмы.

Чем компилятор не ¨автоматический механизм¨?

theNamelessOne ★★★★★
()
Ответ на: комментарий от tailgunner

Это правда лучше?

Конечно, ведь тут минимум спецсимволов, в основном всё по-русски по-английски, так что общий смысл понятен даже тем кто синтаксис не знает.

no-such-file ★★★★★
()
Ответ на: комментарий от theNamelessOne

пример гипотетического синтаксиса Rust (с генериками, лайфтаймами, лямбдами, атрибутами и прочим).

В чём проблема записывать свойства символов в виде plist?

(defvar (i :type int) 42)

(setf x (deref someptr))

foo::<i32>(...) -> ((foo :spec i32) ...)

И т.п. Да писать чуть больше, зато всё понятно и не надо ломать глаза об эти ваши &::->*

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

В чём проблема записывать свойства символов в виде plist?

Ну, на однострочниках легко демонстрировать превосходство синтаксиса с блекджеком и plist'ами. Но ты мне лучше покажи, как будет выглядеть на Lispy Rust следующий фрагмент, а то я сам попробовал, и мне результат не понравился.

#[must_use = "futures are lazy and do nothing unless consumed"]
pub struct Future<T: Send + 'static, E: Send + 'static> {
    pub core: Option<Core<T, E>>,
}

impl<T: Send + 'static, E: Send + 'static> Future<Option<(T, Stream<T, E>)>, E> {
    /// An adapter that converts any future into a one-value stream
    pub fn to_stream(mut self) -> Stream<T, E> {
        stream::from_core(core::take(&mut self.core))
    }
}

impl<T: Send + 'static, E: Send + 'static> Async for Future<T, E> {
    type Value = T;
    type Error = E;
    type Cancel = Receipt<Future<T, E>>;

    fn is_ready(&self) -> bool {
        core::get(&self.core).consumer_is_ready()
    }
}

И это, прошу заметить, далеко не самый навороченный (в плане сахара и синтаксиса) код на Rust.

Постарайся, чтобы код получился идентичным коду на Rust, и при этом синтаксис не получился неоднозначным с учётом того, что атрибуты, спецификаторы видимости и времени жизни, обобщенные аргументы, связанные типы и пр. опциональны.

theNamelessOne ★★★★★
()
Последнее исправление: theNamelessOne (всего исправлений: 1)

Подскажите, вот все говорят карго, карго. А заменяет ли карго makefile в процессе разработки? Умеет ли перекомпилять только измененные файлы? Или в Rust это не требуется? Умеет ли выполнять разные таски (test, clean, ..)?

makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от makoven

Да.

Workflow такой:

  • создаёшь проект (cargo new или cargo init);
  • добавляешь зависимости в файл описания проекта, делаешь cargo update (качает зависимости и обновляет lock-файл, подкоманды build, run, test, bench также скачивают зависимости в случае необходимости);
  • собираешь код командой cargo build;
  • запускаешь код командой cargo run;
  • тестируешь командой cargo test;
  • устанавливаешь командой cargo install.

Есть ещё команды для бенчмарков (bench), генерации документации (doc) и удаления результатов сборки (clean).

Для более продвинутых сценариев существуют ¨скрипты¨ сборки и возможность добавлять новые подкомандны.

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

Как будто я понимаю этот ваш rust... Ну давай пофантазируем, например первый кусок:

(struct (Future :access pub 
                :template (T (+ Send (' static))
                           E (+ Send (' static))
        (core :access pub 
              :value (Option :template (Core: template (T E)))))

Дальше мне просто лениво, но в чём проблема построить AST, ведь оно всё равно строиться компилятором? Хотя это кончено не то что надо, т.к. вообще говоря шаблоны в лисп-синтаксисе просто не нужны, т.к. есть макросы. Если говорить об аналоге rust с синтаксисом лиспа, то выглядеть это будет не то что не 1:1, а совершенно иначе. Например повтор

<T: Send + 'static, E: Send + 'static>
просто режет глаз - в лиспе такие вещи просто делаются отдельной сущностью.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

т.к. вообще говоря шаблоны в лисп-синтаксисе просто не нужны, т.к. есть макросы

В расте есть и шаблоны (дженерики) и макросы.

просто режет глаз - в лиспе такие вещи просто делаются отдельной сущностью.

Какой/как?

DarkEld3r ★★★★★
()

Подскажите, в проекте zinc написано:

Zinc is mostly assembly-free and completely C-free at the moment

c-free я еще могу понять, но почему assembly-free? Это вообще как?

makoven ★★★★★
()
Ответ на: комментарий от makoven

Это значит, что там нет ни одной строчки на С. Это важно, так как включение кусков кода на С приведёт к потере гарантий сохранности памяти и весь Руст пойдёт на смарку. Они бы хотели избавиться целиком и от ассемблера, что и декларируют, но не получится, потому что сами понимаете.

Звучит и вправду немного дико, но сейчас все настолько привыкли к тому, что между ассемблером и языками высокого уровня есть ещё прослойка на С, что, видимо, они решили это явно упомянуть.

Vudod ★★★★★
()
Ответ на: комментарий от no-such-file

Дальше мне просто лениво, но в чём проблема построить AST, ведь оно всё равно строиться компилятором?

Я не говорил, что исходники на Rust нельзя представить в виде sexp, я просто усомнился, что от этого повысится читаемость. Ну я вот не поленился, и перевёл пример на твой синтаксис (я взял на себя смелость добавить в некоторых местах скобок, чтобы избежать неоднозначностей), но получилось говно:

((struct :annotation (must-use "futures are lazy and do nothing unless consumed"))
 (Future :access pub
         :template ((T (+ Send (' static)))
                    (E (+ Send (' static)))))
 (core :access pub
       :value (Option :template ((Core :template (T E))))))

(impl :template ((T (+ Send (' static)))
                 (E (+ Send (' static))))
      (Future :template ((Option :template ((Tuple :template (T (Stream :template (T E))))))
                         E))
      (defun (to-stream :access pub) ((self :modifier ('mut)) :return (Stream :template (T E)))
        (stream:from-core (core-take (deref-mut (field self 'core))))))

(impl :template ((T (+ Send (' static)))
                 (E (+ Send (' static))))
      :trait Async
      (Future :template (T E))
      :assoc-types ((Value T)
                    (Error E)
                    (Cancel (Receipt :template ((Future :template (T E))))))
      (defun is-ready ((self :modifier ('ref)) :return bool)
        ;; Либо clojure-way: (.consumer-is-ready? (core:get (field (ref self) 'core))
        (call-instance-method (core:get (field (ref self) 'core))
                              'consumer-is-ready?)))

Код получился абсолютно нечитаемым. В отличие от Rust, где разнородные синтаксические элементы играют роль «якорей», за которых цепляется глаз, тут без вдумчивого разбора кода невозможно сказать, что делает тот или иной фрагмент, какими свойствами обладает тот или иной тип и т.д.

Хотя это кончено не то что надо, т.к. вообще говоря шаблоны в лисп-синтаксисе просто не нужны, т.к. есть макросы.

Вот с этого места поподробнее. Как макросы могут заменить дженерики?

<T: Send + 'static, E: Send + 'static>

просто режет глаз - в лиспе такие вещи просто делаются отдельной сущностью.

Ну и как подобные вещи делаются в лиспе? Поясню, этот фрагмент означает, что у типа есть два обобщенных параметра T, U, каждый из которых должен реализовывать трейт Send и иметь статическую продолжительность жизни.

theNamelessOne ★★★★★
()
Последнее исправление: theNamelessOne (всего исправлений: 1)
Ответ на: комментарий от Vudod

Они бы хотели избавиться целиком и от ассемблера, что и декларируют, но не получится, потому что сами понимаете.

Не понимаем) Как избавиться от ассемблера, если машинный код строится из ассемблера? Или имеется в виду, что в исходниках zinc почти нет ассемблера?

makoven ★★★★★
()
Ответ на: комментарий от makoven

Не понимаем) Как избавиться от ассемблера, если машинный код строится из ассемблера?

Они имели в виду ¨в исходниках zinc почти нет ассемблерных вставок¨, кмк.

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

Они имели в виду ¨в исходниках zinc почти нет ассемблерных вставок"

Скорее уж «используя zinc, можно писать почти без ассемблерных вставок».

anonymous
()

За ним не заржавеет. Отличный язык. Кресты на дух не переношу, поэтому желаю всех благ поставить на крестах крест.

blue_trava
()

Подскажите, а есть у кого опыт использования раста на arm7? Судя по докам, arm-ы не в приоритете. В табличке напротив Cargo галочка не стоит. Что бы это значило..

makoven ★★★★★
()
Ответ на: комментарий от blue_trava

c++ уже начали копировать свойства раста, c++ core guidelines подразумевает возможность явного указания владения и лайфтаймов, также пишут тулзу, которая может проверять корректность программы по этим параметрам. Так что вполне возможно что закроют 70% фич раста, а оставшихся 30% не хватит чтоб забороть.

anonymous
()
Ответ на: комментарий от anonymous

Потом сверху еще макры и концепты. И нейросеть вместо компилера, чтобы разбираться в этом месиве

makoven ★★★★★
()
Ответ на: комментарий от anonymous

У комитета стандартизации С++ на шее висит огромное количество легаси кода. Они и модули-то с концептами раньше 2020-го вряд ли примут. А 70% фич Rust'а - это где-то ближе к 2030-2040.

red75prim ★★★
() автор топика
Ответ на: комментарий от DarkEld3r

Какой/как?

Т.к. код=данные, то нет никакой проблемы просто взять любой кусок кода и записать в переменную, во всяком случае на этапе компиляции, чтобы потом подставлять, прямо или модифицируя, где нужно по тексту. Если же иметь ввиду встроенный компилятор, то можно и по ходу выполнения программы потом использовать такую «сигнатуру» шаблона.

no-such-file ★★★★★
()
Ответ на: комментарий от red75prim

огромное количество легаси кода

Вот это и есть самый большой минус и тормоз развития плюсов.
За что их и не люблю.

WatchCat ★★★★★
()
Ответ на: комментарий от WatchCat

Вот это и есть самый большой минус и тормоз развития плюсов. За что их и не люблю.

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

Vudod ★★★★★
()
Ответ на: комментарий от theNamelessOne

Код получился абсолютно нечитаемым

Потому что получилась тонна копипасты которую нужно факторизовать завернув в макросы.

Как макросы могут заменить дженерики?

Макросы раста никак не могут, т.к. нет гомоиконности. Если говорить о макросах лиспа то они для того и служат, чтобы генерировать код по описанию, только не с помошью спецсинтаксиса для дженериков, а обычного общего синтаскиса языка.

есть два обобщенных параметра T, U, каждый из которых должен реализовывать трейт Send и иметь статическую продолжительность жизни

Макрос может на этапе компиляции проверять, подходят ли переданные параметры под нужный тип, раз уж тип задаётся в воображаемом псевдорастолиспе с помощью plist.

no-such-file ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.