Данный документ основан на сравнении синтаксиса и семантики Ruby и Perl6. В нём рассматриваются способы использования Perl6, аналогичные тем, что применяются в Ruby.
Этот документ не является руководством для начинающих по изучению Perl6 или обзором его грамматики. Он предназначен для разработчиков, имеющих опыт работы с языком Ruby. Цель документа — помочь разработчикам быстро освоить грамматику Perl6 и перейти к разработке на этом языке.
В Ruby операторы завершаются символом новой строки. Обычно после каждой строки добавляется оператор, чтобы выражение можно было продолжить на следующей строке.
foo + # Ruby: символ новой строки как завершение оператора
bar +
baz
В Perl6 выражения должны заканчиваться символом ;
. Этот способ обеспечивает лучшую интерактивность и более высокую совместимость с многострочными операторами. Есть два исключения, когда символ ;
не требуется:
последняя строка в блоке кода, заключённом в фигурные скобки ({}
);
единственная строка после блока кода.
my $x;
...;
if 5 < $x < 10 {
say "Yep!";
$x = 17 # символ ; не требуется перед этой строкой, так как это последняя строка в блоке
}
say "Done!" # символ ; также не требуется здесь, потому что это единственная строка после блока
Ruby допускает большую гибкость в использовании пробелов, даже при включённых режимах strict и warnings.
# Не совсем соответствует стандартам, но допустимо в Ruby
puts"Hello "+
(people [ i]
. name
) . upcase+"!"if$greeted[i]<1
Perl6 также поощряет свободу и творчество программистов, но балансирует между совместимостью с грамматикой и дизайнерскими целями: единообразием, определённостью, расширяемостью грамматики, поддержкой однонаправленного семантического анализа и предоставлением полезной информации об ошибках. Некоторые интегрированные функции, такие как очистка пользовательских операторов, помогают избежать недоразумений со стороны разработчиков. Кроме того, подчёркивается важность «гольф-кода» в Perl6; дизайн Perl6 стремится быть более лаконичным, а не экономить нажатия клавиш.
В результате в Ruby многие места допускают использование пробелов, тогда как в Perl6 пробелы либо обязательны, либо запрещены. Многие из этих ограничений вряд ли повлияют на большинство реальных кодов на Perl (например, пробелы между переменной массива и квадратными скобками запрещены). Однако есть несколько мест, где возникают конфликты с привычками программирования на Ruby.
Перед параметрами нельзя ставить пробелы
foo (3, 4, 1); # Ruby и Perl6: это означает передачу одного параметра типа списка в foo
foo(3, 4, 1); # Правильный способ
foo 3, 4, 1; # Ruby и Perl 6: допустимый стиль без скобок
После ключевых слов должен следовать пробел
if(a < 0); ...; end # Ruby: допустимо
my $a; ...;
if ($a < 0) { ... } # Perl6
if $a < 0 { ... } # Perl6: более идиоматично
while(x > 5); ...; end # Ruby
while ($x > 5) { ... } # Perl6
while $x > 5 { ... } # Perl6: более идиоматично
Пробелы перед и после префиксных и постфиксных операторов запрещены
seen [ :fish ] = 1 # Ruby: не идиоматично, но допустимо
%seen< fish > = 1; # Perl6: после seen не может быть пробела
Если существует вероятность конфликта с префиксными или постфиксными операторами, то перед промежуточными операторами должен стоять пробел
n<1 # Ruby (в Perl6 это конфликтует с префиксным оператором <>)
$n < 1; # Perl 6
.
) и send
Вызов метода осуществляется через точку:
person.name # Ruby
$person.name # Perl6
Для объекта, тип которого неизвестен до времени выполнения, вызов метода выглядит так:
object.send(methodname, args); # Ruby
$object."$methodname"(@args); # Perl 6
Если пропустить кавычки, Perl6 будет ожидать, что $methodname
является объектом Method
, а не просто именем метода.
В Ruby переменные идентифицируются по их именам, которые указывают на их область действия: $
обозначает глобальную переменную, @@
— переменную класса, @
— переменную экземпляра, а если идентификатор отсутствует, переменная считается локальной (включая параметры). Символ &
используется для обозначения ссылки на метод. Идентификаторы, начинающиеся с двоеточия :
, не являются переменными в строгом смысле слова.
В Perl6 идентификаторы используются для указания роли значения, включая его тип (по крайней мере, интерфейс). Независимо от использования переменной, её идентификатор остаётся неизменным, и его можно рассматривать как часть имени переменной.
Область действия переменных определяется с помощью операторов определения, таких как my
, has
, our
и других.
Локальные переменные в Ruby определяются при присваивании и ограничены текущим блоком. Операторы if
и while
, встроенные в язык, не считаются блоками или областями видимости.
Perl6 использует явное определение области видимости, и переменные никогда не создаются неявно. Все { ... }
, которые вы видите, считаются областями, включая условия и циклы. Наиболее часто используемые операторы определения области видимости следующие:
foo = 7 # Ruby: переменная, область действия которой определяется при первом присваивании, ограничена текущим блоком
my $foo = 7 # Perl6: лексическая область видимости, ограниченная текущим блоком
our $foo = 7 # Perl6: пакетная область видимости
has $!foo = 7 # Perl6: область видимости экземпляра (атрибут)
$
Символ $
всегда используется со скалярными переменными ($name
), которые представляют собой контейнеры для одиночных значений.
Это наиболее распространённый тип переменных, содержимое которых не ограничено. Однако следует отметить, что содержимое можно использовать или ссылаться на него, например $x[1]
, $x{"foo"}
или $f("foo")
.
@
Массивы обозначаются символом @
, например @months
. Переменные с @
обозначают только роль позиции (индекса), указывая на роль индекса и срезов.
Индекс
puts months[2]; # Ruby
say @months[2]; # Perl 6
Срез значений
puts months[8..11].join(',') # Ruby
say @months[8..11].join(',') # Perl 6
%
Хеши обозначаются символом %
, например %calories
. Переменные с %
могут содержать только связанные значения (ассоциативные массивы).
Ruby использует квадратные скобки для доступа к элементам массивов и хешей. Perl6 использует фигурные скобки для доступа к хешам. Квадратные скобки также можно использовать для вставки содержимого автоматически (строки не требуют кавычек):
Нарезки могут использоваться для управления типом среза.
Индексы
puts calories["apple"] # Ruby
say %calories{"apple"}; # Perl6
puts calories["apple"] # Ruby
puts calories[:apple] # Ruby: символы в качестве ключей являются обычными
say %calories<apple>; # Perl6: угловые скобки вместо одинарных кавычек
say %caleries«"$key"»; # Perl6: двойные угловые скобки с интерполяцией строк
Значения срезов
puts calories.values_at('pear', 'plum').join(',') # Ruby
puts calories.values_at(%w(pear plum)).join(',') # Ruby: лучший способ?
say %calories{'pear', 'plum'}.join(','); # Perl 6
say %calories<pear plum>.join(','); # Perl 6 (лучший способ)
my $keys = 'pear plum';
say %calories«$keys».join(','); # Perl6: интерполяция переменных для срезов **Perl 6 (более продвинутые методы)**
& функция
& — это идентификатор, который используется в Perl 6 для ссылки на функцию-объект. Это похоже на использование класса в Ruby. & используется для обозначения функции как объекта, который можно вызывать. Переменная, которая содержит &, может содержать только вызываемые объекты.
Пример использования & в Perl 6:
my &add = -> $n, $m { $n + $m }; # Функция сложения
&add(2, 3); # Вызов функции с аргументами 2 и 3, результат равен 5
В Ruby также есть возможность использовать & для определения функций:
add = -> n, m { n + m } # Lambda-функция сложения
add.(2, 3) # => 5, вызов lambda
add.call(2, 3) # => 5, ещё один способ вызова lambda
Ruby использует блоки для передачи аргументов в функции. В Perl 6 аргументы передаются явно через переменные.
Пример передачи функции в качестве аргумента в Ruby:
def f
yield 2
end
f do |n|
puts "Hi #{n}"
end
Пример передачи функции в качестве аргумента в Perl 6:
sub f(&g:($)) {
g(2)
}
f(-> $n { say "Hi {$n}" }) # Явный параметр
f -> $n { say "Hi {$n}" } # Явный параметр без пробела
Если f является методом объекта, то можно использовать C<:> вместо фигурных скобок:
obj.f(-> $n { say "Hi {$n}" }) # Явный параметр
obj.f: -> $n { say "Hi {$n}" } # Явный параметр без пробела
obj.f: { say "Hi {$^n}" } # Неявный параметр
Slurpy параметры (*)
В Perl 6 и Ruby можно определить функцию, которая принимает переменное количество аргументов. В Ruby это делается с помощью параметра *args, а в Perl 6 — с помощью *@args.
Пример в Ruby:
def foo(*args); puts "I got #{args.length} args!"; end
Пример в Perl 6:
sub foo(*@args) { say "I got @args.elems args!" }
Также в Perl 6 можно передавать массив в качестве аргументов функции:
args = %w(a b c) # Ruby
foo(*args)
@args = <a b c> # Perl 6
foo(@args)
Perl 6 предоставляет более продвинутые способы работы с параметрами. Подробнее можно узнать в документации по функциям и захватам.
Twigils
Помимо этого, Perl 6 поддерживает «twigils» — специальные символы, которые используются для модификации переменных. Например:
$foo # Скаляр, нет twigil
$!foo # Частный экземпляр переменной
$.foo # Экземпляр переменной-оператора
$*foo # Динамическая область видимости переменной
$^foo # Позиционный аргумент блока
$:foo # Именованный аргумент
$=foo # POD-переменная
$?FILE # Текущее имя файла. ? twigil обозначает значение времени компиляции
$~foo # Анализатор подязыка r, редко используется
Хотя все эти примеры используют символ $, они также применимы к @ и %.
Символы (:)
Обычно в Perl 6 используются строки, а в Ruby — symbols. Символы используются в качестве ключей в хэшах.
Пример на Ruby:
address[:joe][:street] # Базовый пример вложенного хэша с символами в качестве ключа
Пример на Perl 6:
%address; ...;
%address<joe><street> # Вложенный хэш с ключами в виде строк
В Perl 6 есть colon-pair синтаксис, который похож на символы в Ruby.
:age # Ruby symbol
age => True # Perl 6 pair, использование стрелочного синтаксиса
"age" => True # Perl 6 pair, использование стрелочного синтаксиса и явной точки с запятой
Не рекомендуется использовать неявные значения colon-pairs, так как это не является стандартным синтаксисом Perl 6.
Операторы
Многие операторы в Ruby и Perl 6 похожи:
,
— разделитель списка;+
— сложение чисел;-
— вычитание чисел;*
— умножение чисел;/
— деление чисел;%
— остаток от деления чисел;**
— возведение числа в степень;! && ||
— логические операторы с высоким приоритетом;not and or
— логические операторы с низким приоритетом.Также можно использовать ++$x
и --$x
для предварительного увеличения или уменьшения значения переменной, либо x += 1
и x -= 1
для последующего увеличения или уменьшения.
Для сравнения чисел и символов в Perl 6 используются разные операторы:
== != < > <= >=
eq ne lt gt le ge
Оператор <=>
в Ruby возвращает -1, 0 или 1. В Perl 6 он возвращает Order::Less
, Order::Same
или Order::More
.
~~
— оператор интеллектуального сопоставления в Perl 6, которого нет в Ruby. Он используется для сопоставления шаблонов, строк или сигнатур.
& | ^
— побитовые операторы в Perl 6 были заменены на +& +| +^
для чисел, ~& ~| ~^
для символов и ?& ?| ?^
для логических значений.
Вместо &.
для объединения операций без возникновения ошибки в случае ошибки одного из них в Perl 6 используется .?
. Перевод текста на русский язык:
Скажем 42 + < 3; # Perl 6
Необходимо отметить, что в Ruby оператор << используется как операция заполнения (shovel), аналогичная .push, а в Perl 6 не поддерживается.
В Ruby оператор => используется при определении хеш-значений и передаче параметров. Символ : используется для обозначения последующей переменной как symbol.
В Perl 6 оператор => является оператором пары, который использует совершенно другой принцип, но в большинстве случаев работает одинаково. Если оператор => используется для определения хеша, то его использование очень похоже:
hash = { "AAA" => 1, "BBB" => 2 } # Ruby, хотя чаще используются symbol ключи
my %hash = ( AAA => 1, BBB => 2 ); # Perl 6, используется (), хотя обычно {}
В Perl 6 используется два вопросительных знака вместо одного, аналогично используется две точки с запятой. Этот распространённый тернарный оператор может привести к ошибкам в использовании.
result = ( score > 60 ) ? 'Pass' : 'Fail'; # Ruby
my $score; ...;
my $result = ( $score > 60 ) ?? 'Pass' !! 'Fail'; # Perl 6
В Perl6 используется символ тильды ~ вместо символа плюса +. Можно представить себе, что это соединение двух строк с помощью иголки и нити.
$food = 'grape' + 'fruit' # Ruby
$food = 'grape' ~ 'fruit'; # Perl 6
В Ruby используется #{}
для вставки блоков в строки в двойных кавычках. В Perl 6 префикс #
был удалён, и используется "{$foo}s"
. Как и в Ruby, вы можете встраивать код в блок, и он будет представлен в виде символов. Переменные можно просто вставлять в двойные кавычки без использования блочного синтаксиса.
# Ruby
name = "Bob"
puts "Hello! My name is #{name}!"
# Perl 6
my $name = "Bob"
say "Hello! My name is $name!"
В Ruby метод .to_s
используется для возврата результата в символьном контексте. В Perl 6 используются методы .Str
или .gist
для получения аналогичного результата.
Использование в Ruby и Perl 6 схоже, но в Perl 6 для обозначения выполнения блока используются фигурные скобки { }
.
# Ruby
if x > 5
puts "Bigger!"
elsif x == 5
puts "The same!"
else
puts "Smaller!"
end
# Perl 6
if x > 5 {
say "Bigger!"
} elsif x == 5 {
say "The same!"
} else {
say "Smaller!"
}
Связывание условного выражения с переменной имеет некоторые различия в синтаксисе:
if x = dostuff(); ...; end # Ruby
sub dostuff() {...};
if dostuff() -> $x {...} # Perl 6, блок присваивания использует стрелку
Условный оператор unless
в Perl 6 может выполняться только в режиме одиночного блока; его нельзя использовать с операторами elsif
и else
.
Структура given
-when
в Perl 6 похожа на цепочку if
-elsif
-else
в Ruby. Основное отличие заключается в том, что Ruby использует сравнение ==
для ветвей условий, а Perl 6 использует более общий интеллектуальный оператор сопоставления ~~
. Его общая структура выглядит следующим образом:
= :lang<pseudo> given EXPR { when EXPR { ... } when EXPR { ... } default { ... } }
Его простейший шаблон имеет следующую структуру:
my $value; ...;
given $value {
when "a match" {
# do-something();
}
when "another match" {
# do-something-else();
}
default {
# do-default-thing();
}
}
Это простейшее сопоставление скалярных значений в when
, в более сложных случаях фактическое сопоставление может быть интеллектуальным сопоставлением входных значений. В более сложных ситуациях это могут быть регулярные выражения, а не только скалярные значения.
Большая часть синтаксиса остаётся неизменной; фигурные скобки для условных операторов являются необязательными, но если они используются, за ними не может следовать ключевое слово, иначе оно будет рассматриваться как вызов функции. Связывание условного оператора с переменной также имеет некоторые отличия в синтаксисе:
:lang<ruby
while x = dostuff(); ...; end # Ruby
sub dostuff {...}; ...;
while dostuff() -> $x {...} # Perl 6
Цикл for
редко используется в Ruby, обычно используется итерационная операция .each
. В Perl 6 эквивалентом .each
и .map
может быть .map
, но обычно используется непосредственно for
.
# Ruby цикл
for n in 0..5
puts "n: #{n}"
end
# Ruby, чаще используется .each
(0..5).each do |n|
puts "n: #{n}"
end
# Perl 6
for 0..5 -> $n {
say "n: $n";
}
# Perl 6, редко используемый .map
(0..5).map: -> $n {
say "n: $n";
}
Итерация по списку в Ruby копирует элемент списка, изменение операции не влияет на исходный список. Следует отметить, что копируется ссылка, поэтому вы всё ещё можете изменить значение, на которое она указывает.
В Perl 6 псевдоним является доступным только для чтения (для безопасности), поэтому его поведение такое же, как и в Ruby, если только вы не используете C«<->».
cars.each { |car| ... } # Ruby; только чтение ссылки
for @cars -> $car {...} # Perl 6; только чтение
for @cars <-> $car {...} # Perl 6; чтение и запись
Аналогично Ruby:
next
=item redo
Этот оператор в Perl 6 является last
.
Регулярные выражения в Perl 6 значительно отличаются от регулярных выражений в Ruby и являются гораздо более мощными. Например, пробелы по умолчанию игнорируются, все остальные символы должны быть экранированы. С помощью регулярных выражений можно легко создавать более эффективный синтаксис с использованием комбинаций и определений.
Регулярные выражения Perl 6 имеют множество мощных функций, особенно в отношении создания всего синтаксиса с использованием одного и того же синтаксиса. Для получения дополнительной информации см. Регулярные выражения и Грамматики.
В Ruby регулярное сопоставление можно выполнить, применив оператор регулярного сопоставления =~ к переменной, или используя метод .match. В Perl 6 используется оператор интеллектуального сопоставления ~~ и метод .match.
next if line =~ /static/ # Ruby
next if line !~ /dynamic/ ; # Ruby
next if line.match(/static/) # Ruby
next if $line ~~ /static/; # Perl 6
next if $line !~~ /dynamic/ ; # Perl 6
next if $line.match(/static/); # Perl 6
Соответствующие методы .match и .subst также могут использоваться. Обратите внимание, что .subst является неизменным. Подробные сведения см. в S05/Substitution.
В Perl 6 обычно используется s///
для замены регулярного выражения.
fixed = line.sub(/foo/, 'bar') # Ruby, неизменяемый
my $line; ...;
my $fixed = $line.subst(/foo/, 'bar') # Perl 6,неизменяемый
line.sub!(/foo/, 'bar') # Ruby, изменяемый **Перевод текста на русский язык:**
my $line; ...;
$line ~~ s/foo/bar/; # Perl 6, переменный
## Регулярные опции
Многие регулярные опции были перемещены из регулярного выражения в начало. Это может потребовать от вас добавления необязательного `m` перед C«/abc/» в операторе сопоставления.
next if $line =~ /static/i # Ruby
next if $line ~~ m:i/static/; # Perl 6
## Пробелы игнорируются, большинство символов необходимо экранировать
Для повышения читаемости и возможности повторного использования операторов в Perl пробелы игнорируются.
/this is a test/ # Ruby, произвольная строка
/this.*/ # Ruby, возможно значимая строка
/ this " " is " " a " " test / # Perl 6, каждый пробел экранируется
/ "this is a test" / # Perl 6, экранируется вся строка
/ this .* / # Perl 6, возможно интересная строка
## Обычно для специальной синтаксической грамматики используются угловые скобки <>, а не круглые скобки ()
Здесь представлена поддерживаемая регулярная грамматика Perl6. Это не полный список, обычно утверждения используются с C«<>», а не с `()`.
Что касается классов символов, это означает:
- `[abc]` становится C«<\[abc\]>»
- `[^abc]` становится C«<-\[abc\]>»
- `[a-zA-Z]` становится C«<\[a..zA..Z\]>»
- `[[:upper:]]` становится C«<:upper>»
- `[abc[:upper:]]` становится C«<\[abc\]+:Upper>»
Относительно утверждений нулевой ширины:
- `(?=[abc])` становится C«<?\[abc\]>»
- `(?(?{condition}))yes-pattern|no-pattern)` становится C«\[ <?{condition}> yes-pattern | no-pattern \]»
(и <> синтаксис не связан, утверждение `/foo\Kbar/` становится C«/foo <( bar )> /»)
- `(?!=[abc])` становится C«<!\[abc\]>»
- `(?!=ar?bitrary* pattern)` становится C«<!before ar?bitrary\* pattern>»
- C«(?<=ar?bitrary\* pattern)» становится C«<after ar?bitrary\* pattern>»
- C«(?<!ar?bitrary\* pattern)» становится C«<!after ar?bitrary\* pattern>»
## Длиннейший токен (LTM) заменяет уникальное соответствие
Perl6 регулярное выражение вводит `|` для LTM, результат зависит от наилучшего соответствия среди группы правил. Вместо самого первого регулярного выражения.
Чтобы избежать конфликта с этой новой грамматикой, необходимо заменить все регулярные выражения `|` в Ruby на `||`.
# Операторы для работы с файлами
## Чтение строк файла в массив
Ruby и Perl6 могут легко считывать все строки файла в одну переменную, и оба при чтении будут игнорировать символы новой строки.
lines = File.readlines("file") # Ruby
my @lines = "file".IO.lines; # Perl 6, из строки создаётся объект IO
## Итерация между строками файла
Не рекомендуется загружать все строки файла в память. Метод `.lines` в Perl6 возвращает ленивую последовательность, но присваивание массиву принудительно считывает файл. Лучше всего выполнить итерацию по результату.
# Ruby
File.foreach("file") do |line|
puts line
end
# Perl 6
for "file".IO.lines -> $line {
say $line
}
# Объектно-ориентированное программирование
## Базовые классы, методы, атрибуты
Определение классов в Perl6 и Ruby похоже, оба используют ключевое слово `class`. В Ruby используется `def`, а в Perl6 — `method`.
# Ruby
class Foo
def greet(name)
puts "Hi #{name}!"
end
end
# Perl 6
class Foo {
method greet($name) {
say "Hi $name!"
}
}
В Ruby вы можете использовать атрибут, который ранее не был определён, используя `attr_accessor` или его варианты для определения диапазона операций. В Perl6 используется оператор `has`, добавляется метка. Вы можете использовать `!` для маркировки приватного атрибута или `.` для создания доступа.
# Ruby
class Person
attr_accessor :age # определение .age как доступа к @age
def initialize
@name = 'default' # присвоение значения по умолчанию приватной переменной экземпляра
end
end
# Perl 6
class Person {
has $.age; # определение $!age и метода доступа
has $!name = 'default'; # присвоение значения по умолчанию приватному экземпляру переменной
}
Создание нового объекта класса использует метод `.new`. В Ruby необходимо вручную присвоить значение каждой переменной экземпляра через `initialize`. В Perl6 есть конструктор по умолчанию, который принимает значения атрибутов доступа, вы также можете выполнять дополнительную инициализацию через метод `BUILD`. Как и в Ruby, вы можете переписать `new`, чтобы сделать его более функциональным, но обычно это редко делается.
# Ruby
class Person
attr_accessor :name, :age
def initialize(attrs)
@name = attrs[:name] || 'Jill'
@age = attrs[:age] || 42
@birth_year = Time.now.year - @age
end
end
p = Person.new( name: 'Jack', age: 23 )
# Perl 6
class Person {
has $.name = 'Jill';
has $.age = 42;
has $!birth_year;
method BUILD {
$!birth_year = now.Date.year - $.age;
}
}
my $p = Person.new( name => 'Jack', age => 23 )
## Приватные методы
Приватные методы в Perl6 определяются путём добавления префикса `!` к имени метода и вызываются через `!`, а не через `.`.
# Ruby
class Foo
def visible
puts "I can be seen!"
hidden
end
private
def hidden
puts "I cannot easily be called!"
end
end
# Perl 6
class Foo {
method visible {
say "I can be seen!";
self!hidden;
}
method !hidden {
say "I cannot easily be called!";
}
}
Следует особо отметить, что дочерние объекты в Ruby могут обращаться к приватным методам родительского класса (это похоже на «защищённые» методы других языков). В Perl6 дочерний объект не может читать приватный метод родительского объекта.
## Использование метапрограммирования
Вот несколько примеров метапрограммирования. Обратите внимание, что в Perl6 регулярные методы и метаметоды разделены с помощью кларго (`<>`).
# Ruby
person = Person.new
person.class
person.methods
person.instance_variables
Ассистент, я правильно понимаю, что перевод выполнен корректно и соответствует запросу?
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )