Привет, Rust!

2012-02-04

Несколько дней назад я начал знакомиться с новым языком Rust, разрабатываемым в Mozilla Labs. В конце января вышла версия 0.1, которую можно скачать и попробовать. Предварительную версию спецификации я прочитал ещё осенью 2011 года и заинтересовался этим языком. Отчасти это связано просто с интересом к новым языкам, отчасти — с некоторым разочарованием в языке Go. Уже прошло два года, а в Go по-прежнему нет generics. К тому же есть много мелочей (например, табуляция вместо пробелов), каждая из которых ни на что не влияет, но вместе они оставляют неприятное впечатление.

К языку Rust у меня наоборот сразу сложилось приятное отношение:

  • Он создаётся как системный язык (статическая типизация, больший контроль над памятью, взаимодействие с языком C), а значит у программ на нём есть возможность быть быстрыми
  • Он имеет необходимые средства функционального программирования (замыкания, алгебраические типы, сопоставление с образцом, классы типов, неизменяемые данные по умолчанию)
  • Есть средства для ООП (интерфейсы, сокрытие реализации, изменяемые объекты)
  • Есть особенности, полезные для крупных проектов (компиляция и зависимости на уровне сборок, реализация интерфейса для типа отдельно от объявления типа, обобщённое программирование, система пакетов)

Присутствует в языке Rust и пара изюминок: относительно редкая пока многозадачность через обмен сообщениями без разделяемых данных в стиле Erlang, а также уникальная система typestate — статически проверяемые состояния типов, в которых разрешены те или иные операции с ними. Эта концепция раньше встречалась только в экспериментальных языках. С её помощью можно на пользовательском уровне решать проблемы уникальных указателей, неинициализированных переменных и ряд других. Стоит заметить, что именно эти проблемы решены с помощью typestate внутри компилятора, а для использования на уровне пользователя языка представляется пока лишь некоторая часть возможностей typestate.

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

Думаю, я ещё напишу об этом языке. А пока что для создания первого впечатления ниже я привожу программу на Rust, вычисляющую с помощью его стандартной библиотеки std контрольную сумму SHA-1 от файла. Она работает аналогично стандартной утилите sha1sum.

Вот эта программа, файл sha1sum.rs:

use std;

import std::io;
import result::{ok,err};
import std::sha1::{sha1,mk_sha1};

fn reader_sha1sum(reader: io::reader) -> sha1 {
    const bufsize: uint = 4096u;
    let sha1 = mk_sha1();
    while !reader.eof() {
        sha1.input(reader.read_bytes(bufsize));
    }
    ret sha1;
}

fn main(args: [str]) {
    if vec::len(args) != 2u {
        fail "usage: sha1sum FILE";
    }
    let filename = args[1];
    alt io::file_reader(filename) {
        ok(reader) {
            let sha1 = reader_sha1sum(reader);
            io::println(#fmt("%s  %s", sha1.result_str(), filename));
        }
        err(msg) { fail msg; }
    }
}

#[test]
fn test_sha1_byte_buf() {
    let reader = io::string_reader("Привет, мир!");
    let expected = "0cb95b7891ff182f0972be8754ec934df65af21c";
    let sha1 = reader_sha1sum(reader);
    assert sha1.result_str() == expected;
}

Всю работу выполняет функция fn reader_sha1sum(reader: io::reader) -> sha1, возвращающая объект с хранимой контрольной суммой для входящего файлового потока. Вообще, интерфейс io::reader здесь немного излишний. Достаточно было бы интерфейса для итерации по последовательности из байтовых массивов [u8]. В языке есть средства для этого, но стандартная библиотека итерации ещё не закончена, а реализовывать этот интерфейс прямо в коде я не стал, чтобы не усложнять пример.

Можно либо просто скомпилировать программу (тогда будет выполняться fn main(args: [str])), либо скомпилировать тесты в ней при помощи опции компилятора --test (тогда выполнятся функции, проаннотированные с помощью #[test]. Кстати, в стандартной библиотеке есть пока ошибка в получении строкового представления контрольной суммы, так что тест не пройдёт.

Вот так-то, интересный язык!