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)

Ответ на: комментарий от quantum-troll

Если бы ты программировал на OCaml'е, то синтаксис раста был для тебя нормальным

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

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

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

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

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

а мне он когда-то напомнил язык программирования Ada

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

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

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

Ещё один перл не нужен.

Ты перл видел то? Раст уже давно его переплюнул. Выбрали они ..= лол. Такой оператор вообще нахрен не нужен, а уж дублировать его — маразм.

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

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

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

А давай ты в своём проекте сделаешь два макроса:

macro_rules! erange { ($from:expr, $to:expr) => {{ $from..$to }} }
macro_rules! irange { ($from:expr, $to:expr) => {{ $from..=$to }} }
И перестанешь плакать от таких мелочей?

anonymous
()

Вопрос. Это аудитория ЛОРа начинает по-другому относится к расту или просто основные хейтеры еще не пришли? Просто во всем треде только хлебушек да пара анонимов пытаются накидывать. Это что, треды про раст тоже становятся скучными? Жаль, жаль.

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

Может, мне и #define all(x) std::begin(x), std::end(x) сделать, а не непонятно зачем нужные рэнджи юзать?

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

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

impl Trait для параметров функций?

Лор, на тебе есть специалисты по теории типов? Обесните для пятилетних, почему

fn belochka<T: Trait>() -> T
и
fn bulochka() -> impl Trait
означают разные вещи, однако
fn belochka<T: Trait>(x: T)
и
fn bulochka(x: impl Trait)
совершенно эквивалентны? Как может быть ∀ эквивалентно ∃?

anonymous
()
Ответ на: impl Trait для параметров функций? от anonymous

fn belochka<T: Trait>() -> T

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

Как может быть ∀ эквивалентно ∃?

«Side note for you type theorists out there [...] impl Trait is universal in an input position, but existential in an output position.» Почему так - опять же ХЗ, tracking issue - вот: https://github.com/rust-lang/rust/issues/34511 ИМХО, делать impl Trait в input position и не следовало, но...

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

Насколько я понимаю, это ошибка и вообще ничего не обозначает.

Это не ошибка. Это означает, что тип возвращаемого значения функции определяется тем, что стоит слева от знака равенства. Например: let x: Cat = belochka(); означает вызов для типа Cat. Альтернативно можно написать let x = belochka::<Cat>();

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

Насколько я понимаю, это ошибка и вообще ничего не обозначает.

Это не ошибка.

Тогда покажи компилируемый код.

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

В отличие от C++, Rust умеет выводить параметры типа rvalue по типу lvalue. Причем даже в сложных случаях:

let mut vector = Vec::new();
vector.push(belochka());
let i: i32= vector[0];

Здесь компилятор сам догадывается, что раз из вектора достали i32, то это Vec<i32>, и что belochka() надо вызывать с T=i32, чтобы код имел смысл. Очень удобно, кстати.

anonymous
()
Ответ на: комментарий от tailgunner
fn belochka<T: Default>() -> T {
    Default::default()
}

fn main() {
    let x: u32 = belochka();
    println!("{:?}", x);
}

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

Вот компилируемый код:

trait Foo {
    fn belka() -> Self;
}

impl Foo for i32 {
    fn belka() -> Self {
        42
    }
}

impl Foo for String {
    fn belka() -> Self {
        "Hello World!".into()
    }
}

fn belochka<T: Foo>() -> T {
    T::belka()
}

let i: i32 = belochka();
println!("{}", i);

let s: String = belochka();
println!("{}", s);
anonymous
()
Ответ на: комментарий от anonymous

Разумеется, последние 4 строки должны быть в main() или еще где-то.

anonymous
()
Ответ на: impl Trait для параметров функций? от anonymous

Как может быть ∀ эквивалентно ∃?

То ли aturon, то ли withouboats (это основные люди ответственные за impl Trait) писал про это блог пост.
Идея в том, что существуют три стадии просветления:

  • pre-rigorous, на которой ты просто пишешь impl Trait не имея понятия о кванторах и их различиях и оно «просто работает».
  • rigorous, на которой ты понимаешь что impl Trait в параметрах функции это ∀, а в возвращаемом значении это ∃.
  • post-rigorous, на которой ты настолько просветлён, что тебе глубоко класть на эти технические детали, ты креативен как бог и код выходит из тебя естественным образом - impl Trait, impl Trait и в продакшн.

Исходя из этого impl Trait был оптимизирован для pre-rigorous школьников и post-rigorous 10x-еров. А на rigorous задротов всем плевать, кого волнует их кукареканье.

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

Так может быть и ..= вводить не стоило?

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

С таким деревянным подходом хацкель им из раста не сделать

дядя, хацкель никому не нужен кроме математиков и академиков. а ратс нужен как замена сишке.

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

Perl если это не однострочник намного читабельнее. А макросы в расте и однострочник переплюнут.

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

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

Это что, треды про раст тоже становятся скучными?

Хайп всё. Раст никому не нужен и вылетел из топ-50 tiobe. Так что зря ты радуешься, хейтеры — индикатор интереса.

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

Он уже убил C++ или ещё нет?

Только в эротических снах разфлакона и ко. А наяву они шпилят на плюсах и похапе, а чо делать. За фапанье на ржу не платят.

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

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

Слишком толсто, попробуй еще.

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

…получился уродец похлеще языков семейства ML…

Шёл бы ты отсюда.

Если тебе что‐то непонятно в ML, то это твоя проблема, а не «ко‐ко‐ко, инопланетяне!»

IchBinFertig
()

RUST мы GO как WEB framework

Пользуясь случаем хотелось бы задать вопрос всем кто читает этот тред. Решил сравнить производительность GO и RUST на простом примере пустой болванки web.

RUST взял пример hyper (вроде как самый быстрый)

#![deny(warnings)]
extern crate hyper;
extern crate pretty_env_logger;

use hyper::{Body, Response, Server};
use hyper::service::service_fn_ok;
use hyper::rt::{self, Future};

static PHRASE: &'static [u8] = b"Hello World!";

fn main() {
    pretty_env_logger::init();

    let addr = ([127, 0, 0, 1], 3000).into();

    // new_service is run for each connection, creating a 'service'
    // to handle requests for that specific connection.
    let new_service = || {
        // This is the `Service` that will handle the connection.
        // `service_fn_ok` is a helper to convert a function that
        // returns a Response into a `Service`.
        service_fn_ok(|_| {
            Response::new(Body::from(PHRASE))
        })
    };

    let server = Server::bind(&addr)
        .serve(new_service)
        .map_err(|e| eprintln!("server error: {}", e));

    println!("Listening on http://{}", addr);

    rt::run(server);
}
~ rustc --version
rustc 1.26.0 (a77568041 2018-05-07)
~ cargo build --release --examples
...
~ siege -c8 -b -t3S  http://127.0.0.1:3000/
** SIEGE 4.0.4
** Preparing 8 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions:		       39555 hits
Availability:		      100.00 %
Elapsed time:		        2.37 secs
Data transferred:	        0.45 MB
Response time:		        0.00 secs
Transaction rate:	    16689.88 trans/sec
Throughput:		        0.19 MB/sec
Concurrency:		        7.22
Successful transactions:       39556
Failed transactions:	           0
Longest transaction:	        0.01
Shortest transaction:	        0.00
приблизительно: 17k TPS

tokyo-minihttp examples/echo.rs:

~ siege -c8 -b -t3S  http://127.0.0.1:8080/
** SIEGE 4.0.4
** Preparing 8 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions:		       16303 hits
Availability:		      100.00 %
Elapsed time:		        2.16 secs
Data transferred:	        0.20 MB
Response time:		        0.00 secs
Transaction rate:	     7547.69 trans/sec
Throughput:		        0.09 MB/sec
Concurrency:		        7.72
Successful transactions:       16303
Failed transactions:	           0
Longest transaction:	        0.02
Shortest transaction:	        0.00
приблизительно: 7.5k TPS

GO:

package main

import (
    "fmt"
    "log"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

~ siege -c8 -b -t3S  http://127.0.0.1:8080/
** SIEGE 4.0.4
** Preparing 8 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions:		       46249 hits
Availability:		      100.00 %
Elapsed time:		        2.19 secs
Data transferred:	        0.79 MB
Response time:		        0.00 secs
Transaction rate:	    21118.26 trans/sec
Throughput:		        0.36 MB/sec
Concurrency:		        7.08
Successful transactions:       46249
Failed transactions:	           0
Longest transaction:	        0.01
Shortest transaction:	        0.00

приблизительно: 21k TPS

Итого: hyper - 17.5k tokyo-minihttp - 7.5k go - 21k

вопрос, за счет чего GO побеждает?

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

Запустить тест секунд на 10 и посмотреть на загрузку ядер в top, например, у интересующего процесса. В идеале, конечно, сама программа, которая тестирует, должна быть запущена на другой машине.

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

https://lonje.blob.core.windows.net/images/messages/pics/Screen_Shot_2018-05-... вот скрин с htop, загрузка на GO

===================

https://lonje.blob.core.windows.net/images/messages/pics/Screen_Shot_2018-05-... это RUST hyper

если что вот инфа о проце

processor	: 7
vendor_id	: AuthenticAMD
cpu family	: 21
model		: 2
model name	: AMD FX-8370 Eight-Core Processor
stepping	: 0
microcode	: 0x600081c
cpu MHz		: 1399.723
cache size	: 2048 KB
physical id	: 0
siblings	: 8
core id		: 7
cpu cores	: 4
apicid		: 23
initial apicid	: 7
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 popcnt aes xsave avx f16c lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs xop skinit wdt lwp fma4 tce nodeid_msr tbm topoext perfctr_core perfctr_nb cpb hw_pstate vmmcall bmi1 arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold
bugs		: fxsave_leak sysret_ss_attrs null_seg spectre_v1 spectre_v2
bogomips	: 8000.32
TLB size	: 1536 4K pages
clflush size	: 64
cache_alignment	: 64
address sizes	: 48 bits physical, 48 bits virtual
power management: ts ttp tm 100mhzsteps hwpstate cpb eff_freq_ro

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

Похоже тривиальное предположение не подтверждается :) Видимо в расте HTTP пока оптимизирован хуже, чем в го.

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

язык всеобщего назначения, куда впихнули вообще всё

Вспомнил PL/1.

Никто из тех, кто в самом деле может вспомнить PL/I, не назовет его PL/1.

tailgunner ★★★★★
()
Ответ на: RUST мы GO как WEB framework от theromis

вопрос, за счет чего GO побеждает?

Всё что ты написал — это словесный понос, пустой и бессмысленный. Код для языков Rust и Go генерирует компилятор виртуальной машины LLVM. Ясень пень просто лапшеобразный кодогенератор где-то неоптимизирован.

А вот сравнения работы изходников написанных на Си скомканных Clang и GCC, вот это да, интересно. Clang — это уже сишный кодогенератор LLVM.

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

я немного посмотрел исходники реализации net/http, там, как в большинстве других go приложений, активно используются go lightthreads, вот похоже за счет них весь выигрыш, потому что RUST целиком полагается на систему, а GO по сути запихивает себя внутрь своей «полуоперационки».

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

Я выложил набор фактов, а вопрос - «почему». И честно говоря, мне все равно чем они пользуются для кодогенерации, меня интересует конечный результат, а он у GO почему то лучше.

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

fn belochka<T: Foo>() -> T {
T::belka()
}

Да, этот код компилируется. Но я ошибся - аналогом "-> impl Trait" было бы «fn belochka<T: Foo>() -> Foo».

tailgunner ★★★★★
()
Ответ на: RUST мы GO как WEB framework от theromis

Решил сравнить производительность GO и RUST на простом примере пустой болванки web.

Это не сравнение производительности Go и Rust, а сравнение производительности их стандартных библиотек работы с HTTP.

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

Пусть будет так, меня все это интересует только в качестве бэкенда. Чего к словам придираться, суть ведь не в этом.

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