Я прочитал спецификацию, но все еще не понимаю, чем my class
отличается от [our] class
. Какие различия и когда использовать?
В чем разница между моим классом и нашим классом в Raku (perl6)?
Ответы (3)
Как и в случае с переменными, my
связывает имя лексически, тогда как our
дополнительно создает запись в окружающем пакете.
module M {
our class Foo {}
class Bar {} # same as above, really
my class Baz {}
}
say M::Foo; # ok
say M::Bar; # still ok
say M::Baz; # BOOM!
Используйте my
для внутренних классов вашего модуля. Конечно, вы все еще можете сделать такие локальные символы доступными для импорта кода, пометив их is export
.
Rational
- person Christoph; 19.11.2015
Объявление области my
подразумевает лексическую область видимости: после объявления символ становится видимым для кода в текущем наборе фигурных скобок. Таким образом, мы склонны называть область в фигурных скобках лексической областью. Например:
sub foo($p) {
# say $var; # Would be a compile time error, it's not declared yet
my $var = 1;
if $p {
$var += 41; # Inner scope, $var is visible
}
return $var; # Same scope that it was declared in, $var is visible
}
# say $var; # $var is no longer available, the scope ended
Поскольку видимость переменной напрямую связана с ее положением в коде, лексическая область видимости действительно помогает рассуждать о программах. Это верно для:
- Программист (как из-за их собственных рассуждений о программе, так и потому, что можно обнаружить больше ошибок и сообщить о них, когда вещи имеют лексическую область видимости)
- Компилятор (лексическая область видимости позволяет проще и лучше оптимизировать)
- Инструменты, такие как IDE (анализ и рассуждения о вещах с лексической областью намного более управляемы)
На раннем этапе разработки языка, который впоследствии стал Raku, подпрограммы по умолчанию не имели лексической области видимости (и имели our
область видимости, как в Perl), однако было решено, что лексическая область видимости является лучшим вариантом по умолчанию. Выполнение вызовов подпрограмм всегда пытается разрешить символ с лексической областью видимости, что означает, что можно было сообщить о необъявленных подпрограммах во время компиляции. Кроме того, набор символов в лексической области видимости фиксируется во время компиляции, и в случае декларативных конструкций, таких как подпрограммы, подпрограмма привязывается к этому символу только для чтения. Это также позволяет такие вещи, как разрешение множественной отправки во время компиляции, проверка аргументов во время компиляции и т. Д. Вероятно, что в будущих версиях языка Raku будет указываться возрастающее количество проверок во время компиляции для элементов программы с лексической областью видимости.
Итак, если лексическая область видимости настолько хороша, почему существует область видимости our
(также известная как пакет)? Короче, потому что:
- Иногда мы хотим делиться вещами шире, чем в пределах заданной лексической области. Мы могли бы просто объявить все лексическим, а затем пометить вещи, которыми мы хотим поделиться с
is export
, но ... - Как только мы дойдем до использования множества разных библиотек, попытка всего экспортировать вещи в единую лексическую область видимости потребителя, скорее всего, приведет к множеству конфликтов.
Пакеты позволяют размещать символы в именах. Например, если я хочу использовать клиенты Cro как для HTTP, так и для WebSockets в одном коде, я могу с радостью использовать оба, и называть их Cro::HTTP::Client
и Cro::WebSocket::Client
соответственно.
Пакеты вводятся деклараторами пакетов, такими как class
, module
, grammar
и (с оговорками) role
. Объявление our
выполнит установку во вложенной конструкции пакета.
Эти пакеты в конечном итоге существуют в пакете верхнего уровня с именем GLOBAL
, что вполне уместно, поскольку они фактически видны глобально. Если мы объявляем переменную с our
-областью видимости, это, таким образом, глобальная переменная (хотя, будем надеяться, с пространством имен), о которой было написано достаточно, чтобы мы знали, что нам следует задуматься и задуматься, является ли глобальная переменная лучшим решением API (потому что , в конечном счете, все, что становится видимым через GLOBAL
, является решением API).
Однако что-то действительно становится немного размытым, так это то, что у нас могут быть лексические пакеты. Это пакеты, которые не устанавливаются в GLOBAL
. Я считаю их чрезвычайно полезными при программировании объектно-ориентированного программирования. Например, у меня могло быть:
# This class that ends up in GLOBAL...
class Cro::HTTP::Client {
# Lexically scoped classes, which are marked `my` and thus hidden
# implementation details. This means I can refactor them however I
# want, and never have to worry about downstream fallout!
my class HTTP1Pipeline {
# Implementation...
}
my class HTTP2Pipeline {
# Implementation...
}
# Implementation...
}
Лексические пакеты также могут быть вложенными и содержать переменные с областью видимости our
, однако они не становятся видимыми глобально (если мы каким-то образом не решим их утечь).
Различным элементам программы Raku приписана область действия по умолчанию:
- Подпрограммы по умолчанию имеют лексическую (
my
) область видимости - По умолчанию для методов используется область видимости
has
(видна только при отправке метода) - Тип (класс, роль, грамматика, подмножество) и объявления модуля по умолчанию для области видимости пакета (
our
) - Константы и перечисления по умолчанию соответствуют области действия пакета (
our
)
Фактически, вещи, которые чаще всего используются по умолчанию для области видимости пакета, а все остальное - нет. (Переменные действительно заставляют нас явно выбирать область видимости, однако наиболее распространенный вариант также является самым коротким для ввода.)
Лично я не решаюсь сделать что-то более видимым, чем настройки языка по умолчанию, однако я часто делаю их менее заметными (например, my
для констант, предназначенных для внутреннее использование и классы, которые я использую для структурирования деталей реализации). Когда я мог что-то сделать, выставив переменную с our
областью видимости в глобально видимом пакете, я по-прежнему часто предпочитаю делать ее с областью видимости my
и предоставлять sub
(экспортируется) или method
(отображается в силу того, что находится в области видимости пакета. class
), чтобы контролировать доступ к нему, чтобы купить себе гибкость в будущем. Я считаю, что делать неправильный выбор сейчас - это нормально, если я дал себе пространство, чтобы сделать его правильнее в будущем, не причиняя никому неудобств. :-)
В итоге:
- Используйте
my
область видимости для всего, что касается деталей реализации - Также используйте
my
область видимости для вещей, которые вы планируетеexport
, но помните, что экспорт помещает символы в единую лексическую область видимости потребителя и рискует столкнуться с конфликтами имен, поэтому будьте внимательны при экспорте особенно общих имен. - Используйте
our
для вещей, которые должны быть разделены, и когда необходимо использовать пространство имен, чтобы избежать конфликтов - В любом случае элементы, которые мы больше всего хотели бы использовать по умолчанию в
our
области видимости, поэтому явное написаниеour
должно дать паузу для размышлений.
Различие my
и our
в основном имеет значение при создании таблицы символов. Например:
my $a; # Create symbol <$a> at top level
package Foo { # Create symbol <Foo> at top level
my $b; # Create symbol <$b> in Foo scope
our $c; # Create symbol <$c> in Foo scope
} # and <Foo::<$c>> at top level
На практике это означает, что все, что our
ограничено, легко передается внешнему миру путем добавления префикса к идентификатору пакета ($Foo::c
или Foo::<$c>
являются синонимами), а все, что my
ограничено, не всегда доступно - хотя вы, безусловно, можете предоставить доступ к нему через , например, геттер-подпрограммы.
В большинстве случаев вы захотите использовать my
. Большинство переменных просто принадлежат их текущей области действия, и никто не занимается этим. Но our
может быть полезен в некоторых случаях:
- константы, которые не отравляют таблицу символов (именно поэтому использование
constant
подразумевает область видимостиour
). Таким образом, вы можете сделать больше перечислений / констант в стиле C, используяpackage Colors { constant red = 1; constant blue = 2; }
, а затем ссылаясь на них как наColors::red
- классы или подпрограммы, которые должны быть доступны, но не должны быть экспортированы (или не должны быть из-за перекрытия символов со встроенными или другими модулями). Экспорт символов может быть отличным, но иногда также приятно иметь пространство имен пакета / модуля, чтобы напоминать вам, с чем идет речь. Таким образом, это также хороший способ управлять параметрами во время выполнения с помощью подпрограмм:
CoolModule::set-preferences( ... )
. (хотя и здесь можно использовать динамические переменные).
Я уверен, что другие прокомментируют другие случаи, когда our
будет полезен, но это из моего собственного опыта.