Чому деякі користувачі цитують назви класів у Perl?


12

Дивлячись Type::Tiny, я бачу, що ім'я класу у виклику до Type::Tiny->newцитується в офіційних документах,

my $NUM = "Type::Tiny"->new(
   name       => "Number",
   constraint => sub { looks_like_number($_) },
   message    => sub { "$_ ain't a number" },
);

Чому це? Це просто стиль? Чи є наслідки для цієї практики?

Відповіді:


7

Візьмемо простіший приклад

package Foo { sub new { die 7  } };
package Bar { sub new { die 42 } };
sub Foo { "Bar" }
Foo->new();

У наведеному вище прикладі константа Fooвирішує значення "Bar", тому це "Bar"->newне викликає "Foo"->new. Як зупинити розв'язання підпрограми? Ви можете це процитувати.

"Foo"->new();

Що стосується наслідків для продуктивності, то ситуація не погіршується, використовуючи рядок, а не барево. Я підтвердив, що optree, створена компанією O=Deparse, однакова. Тому, як правило, здається, що краще цитувати назви класів, якщо ви цінуєте правильність.

Про це йдеться в програмуванні Perl (на жаль в контексті непрямого виклику методу )

... тож ми скажемо вам, що майже завжди можна піти з голою назвою класу, якщо дві речі справжні. По-перше, немає підпрограми з тим самим іменем, що і клас. (Якщо ви дотримуєтесь конвенції, що назви підпрограми, такі як newзапускати малі регістри та імена класів, як ElvenRingпочаткові великі регістри , це ніколи не є проблемою). По-друге, клас завантажений одним із

use ElvenRing;
require ElvenRing;

Будь-яка з цих декларацій гарантує, що Perl знає ElvenRing, це ім'я модуля, яке змушує будь-яке оголене ім’я, як і newраніше, назву класу ElvenRingінтерпретувати як виклик методу, навіть якщо ви, можливо, оголосили власну newпідпрограму в поточному пакеті.

І це має сенс: плутанина тут може статися лише в тому випадку, якщо ваші підпрограми (як правило, малі регістри) мають те саме ім’я, що і клас (як правило, великі регістри). Це може статися лише в тому випадку, якщо ви порушите цю угоду про іменування вище.

tldr; це, мабуть, хороша ідея, щоб процитувати свої назви класів, якщо ви їх знаєте, і ви цінуєте коректність над безладом.

Побічна примітка: або ви можете зупинити розв’язання барева до функції, прикріпивши а ::до кінця її, наприклад, вище Foo::->new.


Дякую Ginnz на Reddit за те, що він мені це вказав , і Тобі Інкстер за коментар (хоча це не мало сенсу для мене в першому читанні).


2
Або Foo::->new, як я дізнався з ікегамі.
моб

@mob так, книга Perl згадує це теж (явно), не впевнений, варто мені це поставити чи ні? Лол.
Еван Керролл

@mob Я також додав це як виноску. Хоча я не впевнений, що мені це подобається.
Еван Керролл

1
Foo::має ту перевагу, яку він попереджає, якщо Fooне існує існуючого пакету
ikegami

1
Спробуйте :: Tiny - кращий приклад, ніж Foo. У використанні вашого коду Foo->можна очікувати, що у вашому пакеті немає такої підпрограми. Але якщо ви використовуєте Try :: Tiny та ряд інших модулів cpan / інших модулів із зовнішнім джерелом, хто скаже, чи використовує хтось із них пакет Try, і якщо так, якщо в ньому є Tiny sub?
ysth

0

Явне цитування імені класу, а не використання голослова (яке трактується як рядок) - один із трьох способів уникнути синтаксичної неоднозначності. Методи викликає класу розділ документації perlobj пояснює.

Оскільки Perl дозволяє використовувати barewords для імен пакетів та імен підпрограми, іноді значення інтерпретації барева трактується неправильно. Наприклад, конструкція Class->new()може бути інтерпретована як 'Class'->new()або. Class()->new()В англійській мові ця друга інтерпретація звучить як "викликати підпрограму з назвою Class(), а потім викликати new()як метод на зворотному значенні" Class(). Якщо Class()в поточному просторі імен є підпрограма, названа Perl, завжди інтерпретуватиметься Class->new()як друга альтернатива: виклик new()на об'єкт, повернутий викликом до Class().

Дивіться цей незвичайний випадок у дії з демонстрацією нижче.

#! /usr/bin/env perl

use strict;
use warnings;

sub Type::Tiny { print "Returning Bogus\n" ; return "Bogus" }

sub Type::Tiny::new { print "Type::Tiny::new\n" }

sub Bogus::new { print "Bogus::new\n" }

my $class = "Type::Tiny";

Type::Tiny->new;
Type::Tiny::->new;
"Type::Tiny"->new;
$class->new;

Його вихід є

Повернення Богуса
Богус: новий
Тип :: Крихітні :: нові
Тип :: Крихітні :: нові
Тип :: Крихітні :: нові

У решті вищезазначеного розділу документації показано, як захиститись від дивної поведінки чи ненавмисних помилок.

Ви можете змусити Perl використовувати першу інтерпретацію ( тобто як виклик методу для названого класу "Class") двома способами. Спочатку ви можете додати ::до назви класу:

Class::->new()

Perl завжди інтерпретуватиме це як виклик методу.

Ви також можете навести ім'я класу:

'Class'->new()

Звичайно, якщо ім'я класу є скалярним, Perl також зробить правильно:

my $class = 'Class';
$class->new();

Що стосується вашого запитання, всі дзвінки нижче є рівнозначними.

Type::Tiny::->new(  );

"Type::Tiny"->new(  );

my $class = "Type::Tiny";
$class->new(  );

Звернення ::до кінця має перевагу - подання корисного попередження. Скажіть, ви випадково набрали

Type::Tinny::->new;

Що виробляє

Bareword "Тип :: Tinny ::" відноситься до неіснуючого пакету в ./ryry 15.
Неможливо знайти об’єктний метод "new" через пакет "Type :: Tinny" (можливо, ви забули завантажити "Type :: Tinny"?) У рядку ./try 15.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.