LINUX.ORG.RU

Rust 1.26

 


5

11

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

Обновить Rust можно с помощью команды:

curl https://sh.rustup.rs -sSf | sh # если у вас еще не установлен rustup
rustup update stable

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

  • Вторая редакция книги «The Rust Programming Language» (почти) готова, и теперь рекомендована по умолчанию для ознакомления вместо первой версии. Также готовится к выходу бумажное издание книги.
  • impl Trait в заголовках функций

    Стало возможно указывать Trait в заголовке функции в качестве типа возвращаемого значения:

    fn foo() -> impl Iterator<Item = i32> {
        // ...
    }
    
    Это позволяет не указывать полный тип в заголовке функции, если с точки зрения API конкретный тип не имеет значения. Такой синтаксис подразумевает статическую диспетчеризацию, в отличие от Box<Trait>.

    Также эта возможность удобна для использования с замыканиями (closures):

    fn foo() -> impl Fn(i32) -> i32 {
        |x| x + 1
    }
    

    Новый синтаксис теперь можно использовать и для типов аргументов фунции:

    // раньше нужно было писать так:
    fn foo<T: Trait>(x: T) {
    
    // сейчас можно так:
    fn foo(x: impl Trait) {
    

  • Неявное разыменование ссылок в сопоставлении с образцом (match, if let, ...)

    Теперь следующий код больше не вызывает ошибку компиляции:

    fn hello(arg: &Option<String>) {
        match arg {
            Some(name) => println!("Hello {}!", name),
            None => println!("I don't know who you are."),
        }
    }
    
    и эквивалентен такому:
    fn hello(arg: &Option<String>) {
        match arg {
            &Some(ref name) => println!("Hello {}!", name),
            &None => println!("I don't know who you are."),
        }
    }
    
    То же работает и для &mut + ref mut.

  • Раскрытие срезов (slice) в сопоставлении с образцом
    fn foo(s: &[u8]) {
        match s {
            [a, b] => (),
            [1, _, _] => (),
            _ => (),
        }
    }
    
  • Закрытые интервалы вида 0..=4, включающие обе границы в диапазон перечисления
        for i in 0..=4 {
            println!("i: {}", i); // выведет 0, 1, 2, 3 и 4
        }
    
  • Новые целочисленные типы i128 и u128
  • Функция main() теперь может возвращать тип Result
    use std::fs::File;
    
    fn main() -> Result<(), std::io::Error> {
        let f = File::open("bar.txt")?;
    
        Ok(())
    }
    
  • Ускорения в работе компилятора
  • Стабилизирована функция std::fs::read_to_string
  • При форматировании через trait Debug теперь можно выводить целочисленные значения в шестнадцатеричном виде:
    assert!(format!("{:02x?}", b"Foo\0") == "[46, 6f, 6f, 00]")
    
  • Номер версии Cargo, начиная с этого релиза, изменяется синхронно с номером версии Rust

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

★★★★★

Проверено: Shaman007 ()
Последнее исправление: tailgunner (всего исправлений: 22)

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

1.26 вышел несколько дней назад. Тебе не приходит в голову, что до таких нюансов, как более информативные сообщения об ошибках, связанных с новой фичей, тупо еще не дошли руки разработчиков? Что юзеры еще не успели обратить на это внимание, создать N-ое количество тредов, создать issues на гитхабе?

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

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

1.26 вышел несколько дней назад.

я так наивно полагаю, что попытки положить в 1 бокс или 1 массив два разных типа с общим трейтом должны были делаться в качестве теста в самом-самом начале того времени, когда изобрели трейты

и вообще — язык с трейтам без этого свойства нафиг не нужен, от слова совсем (вопрос «внутри бокса или снаружи бокса» обсуждаемый и интересный, но каким-то способом это должно быть)

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

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

я наивно полагаю, что ей это очень нужно, а что?

Я уверенно полагаю, что ей это не нужно словсем.

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

я так наивно полагаю, что попытки положить в 1 бокс или 1 массив два разных типа с общим трейтом должны были делаться в качестве теста в самом-самом начале того времени, когда изобрели трейты

Когда-то на ЛОР'е было популярно троллить хаскеллистов вопросом, как написать на Haskell гетерогенный список, т.е. список, содержащий элементы разных типов. Разумеется, напрямую, как в динамически типизированных ЯП, этого сделать невозможно, потому что хаскельный список это типизированная коллекция, и его элементы должны иметь одинаковый тип. Это же справедливо для любого языка с сильной типизацией.

Прошли годы, а кто-то до сих пор этого не понимает.

и вообще — трейты без этого свойства нафиг не нужны, от слова совсем

Это только твоё мнение. Не подскажешь, в каком ЯП типажи позволяют подобное?

(вопрос внутри бокса или снаружи бокса обсуждаемый, но как-то это должно быть)

Ты правда не понимаешь разницу между «внутри бокса» и «снаружи бокса»? Кстати, внутри Box разные типы прекрасно помещаются в коллекции, ведь Box сам по себе это fat указатель (FIXME), а не тип.

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

Никак, такой фичи нет даже во внутреннем API сервиса.

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

...ведь Box сам по себе это fat указатель (FIXME), а не тип.

Обобщённый тип. И толстым указателем Box<SomeId> является только в том случае, если SomeId — это имя трейта.

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

Компилятор пишет, что ожидает один тип, соответствующий типажу Foo, а ему подсовывают другой, тоже соответствующий Foo, но другой.

Ну раз соответствующий, в чем проблема то?

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

Когда-то на ЛОР'е было популярно троллить хаскеллистов вопросом, как написать на Haskell гетерогенный список, т.е. список, содержащий элементы разных типов. Разумеется, напрямую, как в динамически типизированных ЯП, этого сделать невозможно, потому что хаскельный список это типизированная коллекция, и его элементы должны иметь одинаковый тип. Это же справедливо для любого языка с сильной типизацией.

Прошли годы, а кто-то до сих пор этого не понимает.

Безотносительно раста... в хаскеле вполне себе можно в гетерогенные списки. Причём самые что ни на есть настоящие. Где то с 2012 года судя по http://okmij.org/ftp/Haskell/types.html#HList

Вот тут есть туториал http://www.parsonsmatt.org/2017/04/26/basic_type_level_programming_in_haskell...

раздел называется Heterogenous Lists

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

Уже выясняли выше по треду (ну, я выяснял), что это не анонимный тип, а тип, считающийся анонимным в данной конкретной точке с точки зрения вывода типов.

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








fn debugize(val: i32) -> impl std::fmt::Debug {
    val
}

fn debugize_another(val: i32) -> impl std::fmt::Debug {
    val
}

fn want_same_type<T: std::fmt::Debug>(a: T, b: T) {
    println!("{:?} and {:?}", a, b);
}

fn main() {
    want_same_type(debugize(1), debugize(2)); // норм, значения получены из одной функции
    // want_same_type(debugize(1), debugize_another(1)); // тут ошибка, несовпадение типов
}
Из чего следует, что в принципе rustc мог бы давать понятное сообщение типа «ожидается тип возврата debugize(), а получен тип возврата debugize_another()»

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

Проблема в том — и я это только сейчас понял, к сожалению — что ранее в этом треде, я неверно указывал, что impl Trait на выходе функции описывает множество конкретных типов. На самом деле, эта конструкция описывает один единственный тип, но умалчивает его имя, благодаря чему типы можно менять, без рефакторинга API, в котором участвует функция. Горе мне.

Ваша же проблема с www_linux_org_ru в том, что вы хотите применить impl Trait не по назначению, даже несмотря на то, что это желание противоречит самим основам типизации. У любой функции есть тип, и он может быть только одним.

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

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

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

Правда я пока не понял зачем это надо. Лол.

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

Не то чтобы я настаиваю на изучении, просто довожу до сведения. Если с хаскелем опыта нет, то туториал пройти будет непросто, мягко говоря. Тем не менее, это вполне работает. Выглядит как то так в итоге

xs = 'a' ::: "hello" ::: True ::: HNil
вот даже либу нагуглил на хакажд
https://hackage.haskell.org/package/heterolist-0.2.0.0/docs/Data-HeteroList.html
пример у них выглядит вот так
x = (5 :: Int) :- 'a' :- True :- Nil

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

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

Если с хаскелем опыта нет

Нет, я не дорос до хаскеля. Может, в следующем десятилетии…

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

неверно указывал, что impl Trait на выходе функции описывает множество конкретных типов. На самом деле, эта конструкция описывает один единственный тип, но умалчивает его имя

Какая то фигня чесслово. И оно часто нужно вот такое?

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

Ну это и на расте можно


trait Push: Sized {
    fn push<T>(self, v: T) -> (Self, T) {
        (self, v)
    }
}

impl<T> Push for T {}

trait Pop {
    type T;
    type V;
    fn pop(self) -> (Self::T, Self::V);
}

impl<T, V> Pop for (T, V) {
    type T = T;
    type V = V;
    fn pop(self) -> (T, V) {
        self
    }
}


fn main() {
    let heterolist = 1.push("Hello").push("there".to_string()).push(());
    println!("{:?}", heterolist);
    let (rest, head) = heterolist.pop();
    println!("{:?}", rest);
}
red75prim ★★★
()
Последнее исправление: red75prim (всего исправлений: 1)
Ответ на: комментарий от Virtuos86

Это же справедливо для любого языка с сильной типизацией. Прошли годы, а кто-то до сих пор этого не понимает.

даже я тут на лоре когда-то постил код на с++ для коллекции из произвольных типов; там да, есть шероховатости, но он довольно приличный

основная идея емнип в том, что делается класс RootObject и для каждого типа Т делается класс Object<T>, который содержит 1 член типа Т и является наследником RootObject, поэтому в коллекцию из RootObject* можно класть Object<T>*, а значит и Т

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

Всё как раз логично. Impl trait не сообщает конкретный тип, но гарантирует, что одна и та же функция тем не менее будет возвращать значения только этого типа всегда (естественно, если исходники не менять), соответственно нет никакого смысла компилятору истерить о несовместимости типов, если значения получены из одной функции то они одного типа. Другое дело разные функции. Они - мало того что элемент декомпозиции и по возможности не должны иметь неявных зависимостей снаружи, но они ещё и могут быть точкой входа в библиотеку. Компилятору противопоказано знать, что обе версии debugize* возвращают один и тот же тип, чтоб изменение тела функции без изменения прототипа вдруг не стало ломающим.

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

Некоторые Delphi-сты даже после многих лет программирования плевались на begin/end.

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

тип — это предикат

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

когда у каждого значения может быть иерархия предикатов — это убожество в стиле с++ (там правда еще могут быть конверсии типов, что сглаживает проблему, но создает новые)

то, что в расте сделали трейты вместо иерархии классов — это шаг вперед

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

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

Прелюбопытный пример. Но нет ли здесь какой-то внутренней ошибки компилятора?

соглашусь — во всяком случае мне кажется тут есть непоследовательность

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

просто небольшое пояснение:

вот такой (условно)код не скомпиляется

xs = True ::: 'a' ::: "String" ::: HNil
length (hhead xs)
потому что я пытаюсь взять length от булевского значения True

а вот такой скомпиляется
xs = True ::: 'a' ::: "Hello" ::: HNil
length (hhead (htail (htail xs)))
потому что я вычисляю длину стоки "Hello" для чего собственно length и предназначен.

В вашем коде остаются подобные гарантии компилятора?

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

В вашем коде остаются подобные гарантии компилятора?

А ты уверен, что у тебя xs - именно список, а не кортеж?

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

Да и программист на питоне будет более продуктивен чем на расте

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

А в крупных проектах на динамических ЯП, без 100% покрытия тестами и CI вообще печаль по вышеописанным причинам. Нередко вижу как в питоне и js пишут типы в комментариях перед функцией

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

Не вчитывался. А вы не путаете с trait object? Для impl trait нет отношения эквивалентности.

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

Что поражает, так это гигантское количество идиотов в темах про Rust. Их можно разделить на несколько групп:

  • Те кто услышал, что Rust безопасен и даже не хотят слушать, что это означает. Мол безопасен, а есть unsafe, фу какое говно.
  • Те кто увидели новый знак в синтаксисе и разнылись о том мол как теперь код читать, даже не разобравшись зачем это нужно.
  • Те кто берут Си\Асм и делают говно бэнчи на сырых указателях, а потом сравнивают с кодом на rust.
  • Придурки, которые говорят, что в rust нет какой-то фичи, а она есть.

А Вам какие идиотские рассказы про Rust запомнились больше всего?

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

1.26 вышел несколько дней назад. Тебе не приходит в голову, что до таких нюансов, как более информативные сообщения об ошибках, связанных с новой фичей, тупо еще не дошли руки разработчиков? Что юзеры еще не успели обратить на это внимание, создать N-ое количество тредов, создать issues на гитхабе?

Ну так оно и есть.

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

А не разу не сталкивались на практике с такой ошибкой? В достаточно большом крупном проекте, в котором свой код уже не помнишь? И вот такая вот диагностика? Я был в а..е - это минимум. Потому что это реальный ступор. Только пару раз столкнувшись с этим, уже стал побыстрому разруливать. Итог - сообщение компилятор НЕ содержит достаточного количества информации. И речь идет не о более дружелюбном сообщении, а о сообщении с минимально необходимой информацией.

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

Это только твоё мнение. Не подскажешь, в каком ЯП типажи позволяют подобное?

Подозреваю что в Nim можно, или в D.

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

Что поражает, так это гигантское количество идиотов в темах про Rust. Их можно разделить на несколько групп:

Что меня поражает, так это гигантское количество идиотов в темах про все языки программирования, которые восхваляют богомсниспосланный Раст и обзывают критиков Раста идиотами, да еще делят их на группы. У вас, блять, прямо секта какая-то. Вы чего такие нетерпимые? Исключительная нация что лЕ?

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

И вот такая вот диагностика? Я был в а..е - это минимум. Потому что это реальный ступор.

Как говорят американцы, spare me your fake outrage.

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

Т.е. вы утверждаете, что я никогда в жизни не встречал диагностического сообщения компилятора, которое было корректным, но не содержало достаточного количества информации, потому что разные по сути символы в диагностическом выводе были названы одинаково? Я вас правильно понял?

З.Ы. подсказка небольшая - напомню вам, что Раст не единственный язык на земле

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

гетерогенным списком можно конечно назвать что угодно — дело хозяйское; приличное условие вот:

HList lets the user formulate statically checkable constraints: for example, no two elements of a collection may have the same type (so the elements can be unambiguously indexed by their type).

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

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

на расте скорее всего не получится вообще; если получится — интересно глянуть

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

Т.е. вы утверждаете, что я никогда в жизни не встречал диагностического сообщения компилятора, которое было корректным, но не содержало достаточного количества информации

Я утверждаю, что ты ни разу не встречал сообщения, которое обсуждается.

подсказка небольшая - напомню вам, что Раст не единственный язык на земле

Подсказка небольшая - сообщения трансляторов других языков о других ошибках нерелевантны к обсуждению сообщения о конкретной ошибке при трансляции Rust-кода.

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

А Вам какие идиотские рассказы про Rust запомнились больше всего?

Что раст самый любимый язык в каких-то опросах (при этом используют его в работе где-то около 0% тех же опрошенных).

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

Я утверждаю, что ты ни разу не встречал сообщения, которое обсуждается.

Ну так давай уточним тогда, какое сообщение обсуждается? Я же действительно могу ошибаться. Речь идет об этом сообщении?

= note: expected type `impl std::fmt::Debug` (anonymized type)
           found type `impl std::fmt::Debug` (anonymized type)

Подсказка небольшая - сообщения трансляторов других языков о других ошибках нерелевантны к обсуждению сообщения о конкретной ошибке при трансляции Rust-кода.

Т.е. раст существует в своей отдельной реальности и ничего из того, что было наработано в других языках к расту не применимо и нерелевантно?

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

У вас прямо секта какая-то.

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

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

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

Да полюбому уже вычислил, просто вид делает что не знает )))))

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

Ну так давай уточним тогда, какое сообщение обсуждается? Я же действительно могу ошибаться. Речь идет об этом сообщении?

Да.

Т.е. раст существует в своей отдельной реальности и ничего из того, что было наработано в других языках к расту не применимо и нерелевантно?

Spare me your fake outrage.

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

Ну так давайте уточним тогда, какое сообщение обсуждается? Я же действительно могу ошибаться. Речь идет об этом сообщении?

Да.

Ok.

Тогда правильно я понимаю, что в первой строке имеется в виду один символ (symbol, я думаю вы поняли что я имею в виду), а во второй строке другой?

= note: expected type `impl std::fmt::Debug` (anonymized type)
           found type `impl std::fmt::Debug` (anonymized type)

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

Spare me your fake outrage.

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

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

Тогда правильно я понимаю, что в первой строке имеется в виду один символ (symbol, я думаю вы поняли что я имею в виду), а во второй строке другой?

Если речь идет о том, означают ли два упоминания имени std::fmt::Debug разные symbols - нет, это один и тот же трейт. Он реализуется типами обеих значений, которые автор my_val пытается вернуть из функции, но это разные типы, а возврат из такой функции значений разных типов запрещен правилами языка. Поскольку из-за impl Debug в my_int и my_str оба типа анонимизированные (anonymized), их имена не печатаются.

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

Да.

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