[Перевод] Буферы и двоичный ввод и вывод в Perl6
В Perl 5, начиная с версии 5.8, неплохо реализована поддержка Unicode – но люди всё равно жаловались на сложности в её использовании. В основном из-за того, что программисту нужно отслеживать, какие строчки были декодированы, а какие надо обрабатывать как двоичные данные. И нет надёжного способа посмотреть на переменные и понять, двоичные это строчки или текстовые.
В Perl6 эту проблему решили вводом отдельных типов. В Str хранится текст. Строковые литералы в Perl6 имеют тип Str. Двоичные данные хранятся в объектах Buf. И перепутать их уже нельзя. Конвертация между ними осуществляется при помощи методов encode и decode.
my $buf = Buf.new(0x6d, 0xc3, 0xb8, 0xc3, 0xbe, 0x0a);
$*OUT.write($buf);
my $str = $buf.decode('UTF-8');
print $str;
У обеих операций эффект одинаковый – они выводят в стандартный выходной поток «møþ» и перевод строки. Buf.new(...) принимает список целых от 0 до 255 – байты из которых и строится новый буфер. $*OUT.write($buf) выводит буфер из $buf в стандартный выходной поток.
$buf.decode('UTF-8') декодирует буфер и возвращает объект Str (или падает, если в буфере не содержится допустимая строка в UTF-8). Обратная операция — $Buf.encode($encoding). Str можно вывести просто через print.
Естественно, print в процессе работы тоже должен преобразовать строку в двоичное представление. Для этого (и других подобных операций) задана кодировка по умолчанию – UTF-8. В спецификации Perl6 указано, что пользователь может менять настройки по умолчанию (но пока компиляторы этого не поддерживают).
Для чтения можно использовать методы .read($no-of-bytes) (и вы получите Buf) или .get (и вы получите Str). Методы read и write присутствуют не только в файлах и потоках, но и в сокетах.
В Perl 5 можно очень неприятно ошибиться, при помощи конкатенации или каким-то другим образом (join, интерполяция текста) объединив текстовую и двоичную строки. В результате получается «сломанная» строка – но только тогда, когда в ней содержатся байты выше 127. В таких ситуациях чрезвычайно сложно вести отладку кода.
В Perl6 в таком случае вы просто получите ошибку «Cannot use a Buf as a string».