LINUX.ORG.RU

Rust 1.18

 


1

10

Команда Rust анонсирует релиз 1.18.

Обновление предыдущей версии легко:

$ rustup update stable

Сам rustup можно установить здесь.

Основные изменения

Одно из главных изменений - новая версия «The Rust Programming Language», официального учебника по Rust. Он пишется открыто на Github, и имеет более ста авторов. В этом релизе включен черновик второй версии книги, имеющий 19 из 20 глав; двадцатая глава будет готова к релизу 1.19. Купить бумажную версию можно через No Starch Press. Новая версия книги полностью переписана и учитывает последние два года нашего опыта обучения Rust. Вы найдете новые объяснения основных принципов Rust, новые проекты и прочее.

В самом языке улучшено ключевое слово pub. По умолчанию, в Rust объекты приватны; можно использовать pub чтобы сделать их публичными. В Rust 1.18, pub имеет новый вариант:

pub(crate) bar;

Слово в скобках - ограничение, контролирующее степень публичности объекта. Если указанно pub(crate), то bar будет публичным для всего крейта (пакета), но не вне него. Это позволяет декларировать интерфейсы, «внутренне публичные» для пакета, но не доступные для внешних пользователей.

Также можно указать путь, например:

pub(in a::b::c) foo;

Это значит «доступно в иерархии a::b::c, но не в прочих местах».

Для пользователей Windows Rust 1.18 имеет новый атрибут, #![windows_subsystem]. Он работает так:

#![windows_subsystem(console)]
#![windows_subsystem(windows)]

Он контролирует флаг /SUBSYSTEM в компоновщике. На текущий момент доступны только console и windows. Если вы разрабатываете графическое приложение, и не указываете windows, в момент пуска программы всплывет окно консоли. С атрибутом windows этого не произойдет.

Далее, в Rust кортежи, варианты перечисляемых типов и структуры (без атрибута #[repr]) всегда имели неопределенное расположение в памяти. Мы включили автоматическое упорядочивание, которое может привести к уменьшению потребления памяти путем уменьшения необходимого выравнивания. Например:

struct Suboptimal(u8, u16, u8);

В прежних версиях Rust на платформе x86_64 эта структура имела бы размер в шесть байтов. Но согласно исходному коду, ей достаточно должно быть четырех. Остальные два байта - результат выравнивания. Поскольку мы имеем u16, он требует двух байтов. Но в данном случае, он был смещен на один байт из-за предыдущего u8. Для последнего же u8 требуется еще один байт выравнивая. В итоге, мы имеем 1 + 1 (пусто) + 2 + 1 + 1 (пусто) = 6 байтов.

Но что если структура выглядит так?

struct Optimal(u8, u8, u16);

Эта структура оптимально выравнена; u16 находится на рубеже двух байтов, как и остальная структура. Выравнивание не требуется. Это дает нам 1 + 1 + 2 = 4 байта.

При дизайне Rust мы оставили физическое расположение данных в памяти неопределенным как-раз по этой причине; любой safe-код (не следующий по «сырым» указателям) не будет затронут подобной оптимизацией. Благодаря этому, мы можем научить компилятор оптимизировать Suboptimal в Optimal автоматически. В Rust 1.18 обе структуры занимают в памяти размер в четыре байта.

Мы долго планировали это изменение; оно было и ранее в нестабильной версии Rust, но некоторые программисты писали unsafe-код, который предполагал определенное расположение данных в памяти. Если вам необходима гарантия, что физическое расположение в памяти в точности совпадает с расположением вариантов в исходном коде (например, при обращению к оболочкам Cи-кода), пометьте вашу структуру с атрибутом #[repr(C)].

Напоследок, улучшено время компиляции; например, компиляция самого rustc теперь на 15%-20% быстрее.

Стабилизированы следующие библиотеки:

  • Child::try_wait, неблокирующая форма Child::wait.
  • HashMap::retain и HashSet::retain - версия существующего retain от Vec<T> теперь и у этих двух структур.
  • PeekMut::pop позволяет взять ранее прочитанный верхний элемент от BinaryHeap<T> без необходимости повторно упорядочивать кучу.
  • TcpStream::peek, UdpSocket::peek, UdpSocket::peek_from позволяют прочесть крайний элемент у потока или сокета.

Новый функционал Cargo

Cargo добавил поддержку системы управления версиями Pijul, который написан на Rust:

cargo new my-awesome-project --vcs=pijul

У Cargo несколько новых флагов, дополняющих --all: --bins, --examples, --tests и --benches позволяют собрать все программы указанных типов.

И наконец, Cargo теперь поддерживает Haiku и Android.

Подробнее об изменениях написано здесь.

>>> Подробности



Проверено: Shaman007 ()
Последнее исправление: cetjs2 (всего исправлений: 7)
Ответ на: комментарий от eao197

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

https://i.imgur.com/v0exTK1.png

https://m.imgur.com/kmjM1JQ

И куски кода в твиттере

// a go quiz
x := []int{1, 2}
y := x[:1]
y = append(y, 99)
fmt.Printf("%v", x)
// Guess what gets printed?
pftBest ★★★★
()
Ответ на: комментарий от Virtuos86

А вот это спорно, судя по тому же содержанию треда :}

Просто про мейнстрим спорить уже всем надоело, а так те же плюсы/джава вызывают «ненависти»/насмешек не меньше.

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

Если на Go перейдут многие веб-разрабочики, сегодня используещие, например, Ruby или PHP

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

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

Ну и где здесь отстрел ног?

По твоему это всем очевидное поведение? А если взятие слайса будет в другой функции? Что, каждый раз когда хочешь сделать append нужно перечитать два раза весь код, а не сохранил ли где-то кто-то указатель на оригинальный слайс?

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

По твоему это всем очевидное поведение?

Отсутствие иммутабельности — это обычное дело в мейнстримовых языках. Что в Python, что в Ruby, что в Java, что в C#, можно получить две разных ссылки на один и тот же Array и модифицировать этот Array из разных мест. Для Go разработчика здесь не будет ничего нового по сравнению с каким-нибудь Python-ом.

С другой стороны, заставь обычного Go-фера разбираться с мутабельными и иммутабельными ссылками, с невозможностью одновременно иметь мутабельные и иммутабельные ссылки на один и тот же объект, с надобностью водить хороводы вокруг Rc<RefCeil<T>> и он вам скажет: спасибо, но для моих задач все это просто оверкилл, я лучше аккуратненько свой код напишу, но не буду себя голову забивать способами борьбы с этим вашим borrow checker-ом.

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

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

FTFY

Что в Python, что в Ruby, что в Java, что в C#

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

Например питон на который должен быть похож го ведет себя правильно в этом случае

>>> x = [1, 2]
>>> y = x[:1]
>>> y.append(99)
>>> x
[1, 2]
>>> y
[1, 99]

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

Проведение, конечно, документированное (хотя и неявно), но для человека который не до конца осознал, что:

  • срез — это эффективно указатель, размер и максимальный размер;
  • всё в го передаётся по значению, как в си (передача по указателю рассматривается как передача значения указателя);
  • append, если хватает места, расширяет slice in-place.

Такое поведение (затирание «несвязанного» среза) будет неприятными сюрпризом. Правда, если между этими действиям не произошла релокация среза x, тогда не затрёт. Причём обосновывать это явностью операции выделения памяти не получится, append сам неявно выделяет память и копирует нижележащий массив, если не хватает capacity.

Также стоит сказать, что append де-факто является generic-методом, которые, якобы, сложные. И является built-in'ом, т.к. в библиотеке его не реализуешь из-за отсутствия generics. Зато работа с interface{} столь проста и удобна, что рекомендуется как единственный, подчас нерабочий, метод написания обобщенных алгоритмов.

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

Например питон на который должен быть похож го ведет себя правильно в этом случае

Есть у меня подозрение, что этот пример на Python-е не аналогичен. У вас y — это не ссылка на часть x, это копия части x.

Ну а то, что вы в другом языке получаете не то поведение, как ожидаете в Python, ну ктож виноват.

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

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

Для Go разработчика здесь не будет ничего нового по сравнению с каким-нибудь Python-ом.
Ну а то, что вы в другом языке получаете не то поведение, как ожидаете в Python, ну ктож виноват.

/0

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

Видимо, у нас сильно разные представления об «отстреле» ног. Ибо вот здесь, в совершенно некошерном Go-шном коде, наплевав на все правила Go, ничего нигде не портится:

package main

import "os"
import "fmt"

func main() {
  f, _ := os.Open("nonexistent.file")
  b1 := make([]byte, 5)
  n1, _ := f.Read(b1)
  fmt.Printf("%d bytes: %s\n", n1, string(b1))
}
Сравните это с C. С попыткой использовать FILE*, возвращенный неудачным обращением к fopen.

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

Да всё херня, что Вы как школьник на всё внимание обращаете? =)

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

Ох-ох-ох, а когда eao197 дебилами и в тугоумстве всех подряд называет, чьё мнение с его не совпадает, это нормально? XD Я смотрю на лоре все равны, но кто-то ровнее? ^_^

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

Я как-то криво выразился, вчера голова разрывалась от давления :). Имелось в виду «вам не надоело его терпеть?»

Virtuos86 ★★★★★
()

Посмотрел я на этот Раст, и сразу возникли непонятки. Ведь он пиарится как ЯП для системного программирования, так? Как там работают с массивами переменной длины? Возьмем жизненный пример: разбор пакета, переданного по сети:

struct DataUnit
{
    enum class Type : uint32_t { INT32, INT64 } type;
    union
    {
        int32_t i32;
        int64_t i64;
        // ... и иные данные
    } data;
};

bool getDataUnit(uint32_t *chunk, std::size_t len, DataUnit& dataUnit)
{
    // Ради краткости примера пропускаем необходимые проверки на размеры буфера chunk
    DataUnit::Type tp = (DataUnit::Type)*chunk++;
    if (DataUnit::Type::INT32 == tp)
    {
        dataUnit.data.i32 = *(int32_t*)chunk;
    }
    else if (DataUnit::Type::INT64 == tp)
    {
        dataUnit.data.i64 = *(int64_t*)chunk;
    }
    else
        return false;
    dataUnit.type = tp;

    // ... и т.д с иными данными

    return true;
}
seiken ★★★★★
()
Ответ на: комментарий от seiken

Потестить можно тут: http://play.integer32.com/?gist=bcabf9df7655a0b8674270bb8d214c10&version=...

extern crate byteorder;

use std::error::Error;
use std::io::Cursor;
use byteorder::{BigEndian, ReadBytesExt};

#[derive(Debug)]
enum DataUnit {
    Int32(i32),
    Int64(i64),
    Pair {
        x: f32,
        y: f32,
    }
}

fn get_data_unit(chunk: &[u8]) -> Result<DataUnit, Box<Error>> {
    let mut rdr = Cursor::new(chunk);
    let t = rdr.read_u8()?;
    Ok(match t {
        0 => DataUnit::Int32(rdr.read_i32::<BigEndian>()?),
        1 => DataUnit::Int64(rdr.read_i64::<BigEndian>()?),
        2 => DataUnit::Pair {
            x: rdr.read_f32::<BigEndian>()?,
            y: rdr.read_f32::<BigEndian>()?,
        },
        _ => Err("invalid type")?,
    })
}

fn main() {
    let good_chunk = [0, 1, 2, 3, 4];
    println!("good: {:?}", get_data_unit(&good_chunk));
    
    let bad_chunk = [1, 1, 2, 3, 4];
    println!("\nbad: {:?}", get_data_unit(&bad_chunk));
}

pftBest ★★★★
()

Внезапный вопрос, как из

hyper::header::HttpDate
сделать что-то умеющее в
tokio_postgres::types::ToSql + tokio_postgres::types::FromSql
и наоборот?

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

Если не релизованы трейты, то форкнуть и реализовать в tokio-postgres за feature-gate поддержки Hyper, а потом оформить пулл-реквест будет, наверное, лучшим вариантом.

А на месте — обернуть в HttpDate в NewType и для него реализовать нужные конверсии.

mersinvald ★★★★★
()

Кстати, исходной код Pijul относительно идиоматичен как пример кода для приложений на Rust (более, чем например, сам компилятор rustc который должен из примитивов строить всю стандартную библиотеку).

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

Как пример идиоматичного Rust, структуры данных отделены от алгоритмов их использующих. Например, в Pijul эти структуры находятся в backend.rs. Там и unsafe много, и операций с лайфтмаймами. На зато в алгоритме патча, длиной в 1500 строк, синтаксис лайфтаймов ('a итп.) встречается лишь на одной строке, а unsafe не встречается ни разу. Таким образом, можно отделить мух от котлет безопасную работу с данными в памятью, от собственно отладки алгоритма патчей.

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

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

Зачем это может понадобится? Если надо сравнить ассемблер, то есть godbolt, а если кусок кода показать то есть playpen который сразу и выполнять его умеет.

В чем смысл этого сайтика который ты везде рекламишь?

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

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

А просто смотреть два текста рядом без никакой подсветки совсем не интересно.

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

Когда ты можешь за 5 минут тут же подключить сишные файлы и сразу начать скрипты писать, которые дергают функционал «сверху»

Это про luajit еще можно с натяжкой сказать. Для обычной lua, чтобы задействовать сишный код, сначала придется написать большую партянку на Си + Lua C API. И этот API, с его стеком, я бы не назвал верхом удобства

Однажды я писал такой биндинг для своей сишной либы (работа с девайсом через COM-порт). И биндинг получился такого же размера, что и либа

Что же до самой Lua.. На js (особенно на современном) писать в разы приятнее

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

и он вам скажет: спасибо, но для моих задач все это просто оверкилл, я лучше аккуратненько свой код напишу, но не буду себя голову забивать способами борьбы с этим вашим borrow checker-ом

Если Когда-нибудь Go начнут использовать повсеместно для огромных проектов. И если гугл к тому времени не добавит дженериков и всяких взрослых проверок времени компиляции.. То эти штуки добавит какой-нибудь фейсбук или майкрософт (смотреть flow и typescript). И это будет невероятно ублюдочное, но необходимое решение (смотреть flow и typescript)

makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.