#Private attribute example
class C {
has $!w; #private attribute
multi method w { $!w } #getter method
multi method w ( $_ ) { #setter method
warn “Don’t go changing my w!”; #some side action
$!w = $_
}
}
my $c = C.new
$c.w( 42 )
say $c.w #prints 42
$c.w: 43
say $c.w #prints 43
#but not
$c.w = 44
Cannot modify an immutable Int (43)
пока разумно, а потом
#Public attribute example
class C {
has $.v is rw #public attribute with automatic accessors
}
my $c = C.new
$c.v = 42
say $c.v #prints 42
#but not
$c.v( 43 ) #or $c.v: 43
Too many positionals passed; expected 1 argument but got 2
Мне нравится непосредственность назначения '=', но мне нужна легкость вставки побочных действий, которые обеспечивают несколько методов. Я понимаю, что это два разных мира, и что они не смешиваются.
НО - я не понимаю, почему я не могу просто пойти $ cv (43), чтобы установить публичный атрибут
- Я чувствую, что Раку подсказывает мне не смешивать эти два режима - некоторые атрибуты приватные, а некоторые общедоступные, и что давление направлено на метод метода (с некоторыми: сахар из толстой кишки) - это цель замысла Раку?
- Я что-то пропустил?
is rw
указано. Возврат прокси не приведет к изменению количества допустимых параметров в методе доступа.= foo
и.(foo)
настройку, и включение), и побочные эффекты могут быть выполнены в обоих случаях (но не только при извлечении): tio.run/…Ответы:
Справедливо сказать, что Раку не совсем незавершен в этой области. Ваш вопрос затрагивает две темы в дизайне Raku, которые стоит немного обсудить.
Раку имеет первоклассные l-значения
Раку широко использует l-значения как первоклассную вещь. Когда мы пишем:
Генерируемый метод:
is rw
Здесь указывает на то, что метод возвращающий л-значение - то есть, то , что может быть назначен. Таким образом, когда мы пишем:Это не синтаксический сахар: на самом деле это вызов метода, а затем к его результату применяется оператор присваивания. Это работает, потому что вызов метода возвращает
Scalar
контейнер атрибута, который затем может быть назначен в. Можно использовать связывание, чтобы разделить это на два шага, чтобы увидеть, что это не тривиальное синтаксическое преобразование. Например, это:Будет присваивать атрибут объекта. Этот же механизм стоит за многими другими функциями, включая назначение списка. Например, это:
Работает,
List
создавая контейнеры$x
и$y
, , а затем оператор присваивания в этом случае выполняет итерацию каждой стороны попарно, чтобы выполнить присваивание. Это означает, что мы можем использовать средстваrw
доступа к объектам там:И все это просто естественно работает. Это также механизм назначения для секций массивов и хэшей.
Можно также использовать
Proxy
для создания контейнера l-значения, где поведение чтения и записи находится под вашим контролем. Таким образом, вы можете положить побочные действия вSTORE
. Однако...Раку поощряет семантические методы над «сеттерами»
Когда мы описываем ОО, часто встречаются такие термины, как «инкапсуляция» и «скрытие данных». Ключевая идея здесь заключается в том, что модель состояния внутри объекта, то есть способ представления данных, необходимых для реализации его поведения (методов), может свободно развиваться, например, для обработки новых требований. Чем сложнее объект, тем более освобождающим становится это.
Однако методы получения и установки - это методы, которые неявно связаны с состоянием. Хотя мы можем утверждать, что достигаем сокрытия данных, потому что мы вызываем метод, а не напрямую обращаемся к состоянию, мой опыт показывает, что мы быстро оказываемся в месте, где внешний код выполняет последовательности вызовов установщика для выполнения операции, которая форма особенность зависти анти-шаблон. И если мы делаем это , это довольно уверен , что мы в конечном итоге с логикой снаружи объекта , который делает смесь получения и установки операций для достижения операции. Действительно, эти операции должны были быть представлены как методы с именами, которые описывают то, что достигается. Это становится еще более важным, если мы находимся в параллельной обстановке; хорошо спроектированный объект часто довольно легко защитить на границе метода.
Тем не менее, многие виды использования
class
действительно являются типами записей / продуктов: они существуют, чтобы просто сгруппировать кучу элементов данных. Не случайно, что.
сигил не только генерирует аксессор, но и:class Point { has $.x; has $.y; }
может быть создан какPoint.new(x => 1, y => 2)
), а также отображает его в.raku
методе сброса..Capture
объект по умолчанию , что означает, что мы можем использовать его при деструктурировании (напримерsub translated(Point (:$x, :$y)) { ... }
).Что бы вы хотели, если бы вы писали в более процедурном или функциональном стиле и использовали его
class
как средство для определения типа записи.Дизайн Raku не оптимизирован для умных действий в сеттерах, потому что это плохо для оптимизации. Это выше того, что нужно для типа записи; на некоторых языках мы можем утверждать, что хотим сделать проверку того, что присваивается, но в Raku мы можем обратиться к
subset
типам для этого. В то же время, если мы действительно занимаемся проектированием ОО, нам нужен API осмысленного поведения, которое скрывает модель состояния, а не думать с точки зрения геттеров / сеттеров, что, как правило, приводит к невозможности совместного размещения данные и поведение, что в любом случае является основной целью ОО.источник
Proxy
s (хотя я и предложил это ха). Единственный раз, когда я нашел их очень полезными для меняLanguageTag
. Внутренне$tag.region
возвращает объект типаRegion
(как он хранится внутри), но реальность такова, что это гораздо более удобно для людей , чтобы сказать$tag.region = "JP"
более$tag.region.code = "JP"
. И это на самом деле только временно, пока я не смогу выразить приведениеStr
в типе, например,has Region(Str) $.region is rw
(который требует двух отдельных запланированных, но низкоприоритетных функций)Ну, это действительно зависит от архитектора. А если серьезно, нет, это просто не стандартный способ работы Раку.
Теперь вполне возможно создать
Attribute
признак в модульном пространстве, что-то вроде этогоis settable
, что создаст альтернативный метод доступа, который будет принимать одно значение для установки значения. Проблема с этим в основном заключается в том, что я думаю, что в мире существует 2 лагеря с возвращаемым значением такого мутатора: вернет ли оно новое значение или старое значение?Пожалуйста, свяжитесь со мной, если вы заинтересованы в реализации такой черты в модульном пространстве.
источник
В настоящее время я подозреваю, что вы просто запутались. 1 Прежде чем я коснусь этого, давайте начнем с того, что вас не смущает:
Вы можете делать все эти вещи. То есть вы используете
=
присваивание, и несколько методов, и «просто уходите$c.v( 43 )
», все одновременно, если вы хотите:Возможный источник путаницы 1
За кулисами
has $.foo is rw
генерирует атрибут и единственный метод в соответствии с:Выше не совсем верно, хотя. Учитывая поведение, которое мы наблюдаем, автоматически сгенерированный
foo
метод компилятора так или иначе объявляется так, что любой новый метод с тем же именем молча скрывает его.2Поэтому, если вы хотите один или несколько пользовательских методов с тем же именем, что и атрибут, вы должны вручную скопировать автоматически сгенерированный метод, если вы хотите сохранить поведение, за которое оно обычно отвечает.
Сноски
1 См. Ответ jnthn, чтобы получить четкий, подробный и авторитетный отчет о мнении Раку о частном и общедоступном методах получения / установки и о том, что он делает за кулисами, когда вы объявляете публичные методы получения / установки (т.е.
has $.foo
).2 Если был объявлен автоматически созданный метод доступа для атрибута
only
, то Raku, я полагаю, сгенерирует исключение, если будет объявлен метод с тем же именем. Если он был объявленmulti
, то он не должен быть скрыт, если новый метод также был объявленmulti
, и должен генерировать исключение, если нет. Таким образом, автоматически сгенерированный метод доступа объявляется ни с помощью, ни с чем-only
либо,multi
но позволяет каким-либо образом скрывать тени.источник