Объектно-ориентированный синтаксис конструктора Perl и названные параметры

Я думаю , некоторая единственная вещь в какой-то момент должна быть ответственна за обеспечение допустимых отношений.

, Например, Ruby on Rails не использует внешние ключи, но он проверяет все отношения сам. Если Вы только когда-либо получаете доступ к своей базе данных из того приложения Ruby on Rails, это прекрасно.

Однако, если у Вас есть другие клиенты, которые пишут в базу данных, затем без внешних ключей, они должны реализовать свою собственную проверку. У Вас тогда есть две копии кода доступа, которые, скорее всего, отличаются, который любой программист должен быть в состоянии сказать, кардинальный грех.

В той точке, внешние ключи действительно необходимы, поскольку они позволяют Вам перемещать ответственность перед единственной точкой снова.

27
задан zdim 20 September 2018 в 21:21
поделиться

6 ответов

Чтобы ответить на основную суть вашего вопроса, поскольку хэш может быть инициализирован как список пар ключ => значение , вы можете отправить такой список в функцию а затем присвоить хешу @_ . Это стандартный способ выполнения именованных параметров в Perl.

Например,

sub foo { 
    my %stuff = @_;
    ...
}

foo( beer => 'good', vodka => 'great' );

Это приведет к % stuff в подпрограмме foo , имеющей хэш с двумя ключами, пиво и водка и соответствующие значения

Теперь в OO Perl есть некоторые дополнительные морщины. Каждый раз, когда вы используете оператор стрелки ( -> ) для вызова метода, все, что было слева от стрелки, застревает в начале массива @_ .

Итак, если вы скажете Foo-> new (1, 2, 3) ;

Тогда внутри вашего конструктора @_ будет выглядеть так: ('Foo', 1, 2, 3) .

Итак, мы используем shift , который без аргумента работает с @_ неявно, чтобы получить этот первый элемент из @_ и присвоить его $ type . После этого в @_ остались только наши пары имя / значение, и мы можем назначить его непосредственно хешу для удобства.

Затем мы используем это значение $ type для благословите . Все, что делает bless , - это берет ссылку (в вашем первом примере хэш-ссылку) и говорит: «Эта ссылка связана с определенным пакетом». Алаказзам, у вас есть объект.

Помните, что $ type содержит строку 'Foo', которая является именем нашего пакета. Если вы не укажете второй аргумент для bless , он будет использовать имя текущего пакета, который также будет работать в этом примере, но будет не работают для унаследованных конструкторов.

53
ответ дан 28 November 2019 в 04:07
поделиться

Ваш вопрос не касается OO Perl. Вы запутались в структурах данных.

Хэш может быть инициализирован с помощью списка или массива:

my @x = ('High' => 42, 'Low' => 11);
my %h = @x;

use Data::Dumper;
print Dumper \%h;
$VAR1 = {
          'Low' => 11,
          'High' => 42
        };

Когда вы вызываете метод по ссылке bless ed, ссылка добавляется к списку аргументов, который получает метод:

#!/usr/bin/perl

package My::Mod;

use strict;
use warnings;

use Data::Dumper;
$Data::Dumper::Indent = 0;

sub new { bless [] => shift }

sub frobnicate { Dumper(\@_) }

package main;

use strict;
use warnings;

my $x = My::Mod->new;

# invoke instance method
print $x->frobnicate('High' => 42, 'Low' => 11);

# invoke class method
print My::Mod->frobnicate('High' => 42, 'Low' => 11);

# call sub frobnicate in package My::Mod
print My::Mod::frobnicate('High' => 42, 'Low' => 11);

Вывод :

$VAR1 = [bless( [], 'My::Mod' ),'High',42,'Low',11];
$VAR1 = ['My::Mod','High',42,'Low',11];
$VAR1 = ['High',42,'Low',11];
9
ответ дан 28 November 2019 в 04:07
поделиться

Некоторые моменты, которые еще не были рассмотрены:

В Perl конструктор - это просто подпрограмма называется новая .

Не совсем так. Вызов конструктора new - это просто соглашение. Вы можете называть это как угодно. С точки зрения perl, в этом имени нет ничего особенного.

bless $ self, $ type;

Оба ваших примера не возвращают результат bless явно. Надеюсь, вы в любом случае знаете, что они делают это неявно.

9
ответ дан 28 November 2019 в 04:07
поделиться

Если вы назначаете массив хешу, perl обрабатывает чередующиеся элементы в массиве как ключи и значения. Ваш массив выглядит как

my @array = (key1, val1, key2, val2, key3, val3, ...);

. Когда вы назначаете это% hash, вы получаете

my %hash = @array;
# %hash = ( key1 => val1, key2 => val2, key3 => val3, ...);

Это еще один способ сказать, что в синтаксисе конструкции perl list / hash, "," и "=>" означают то же самое.

8
ответ дан 28 November 2019 в 04:07
поделиться

В Perl все аргументы подпрограмм передаются через предопределенный массив @_ .

Сдвиг удаляет и возвращает первый элемент из массива @_ . В Perl OO это вызывающий метод - обычно это имя класса для конструкторов и объект для других методов.

Хеши сглаживаются и могут быть инициализированы списками. Это распространенный трюк - имитировать именованные аргументы подпрограмм. например

Employee->new(name => 'Fred Flintstone', occupation => 'quarry worker');

Игнорирование имени класса (которое смещено), нечетные элементы становятся ключами хеширования, а четные элементы - соответствующими значениями.

my $ self = {} создает новый хэш ] ссылка для хранения данных экземпляра. Функция bless - это то, что превращает обычную хеш-ссылку $ self в объект. Все, что он делает, - это добавляет некоторые метаданные, которые идентифицируют ссылку как принадлежащую классу.

5
ответ дан 28 November 2019 в 04:07
поделиться

.1. In Perl, the constructor is just a subroutine called new.

Yes, by convention new is a constructor. It may also perform initialization or not. new should return an object on success or throw an exception (die/croak) if an error has occurred that prevents object creation.

You can name your constructor anything you like, have as many constructors as you like, and even build bless objects into any name space you desire (not that this is a good idea).

.2. I don't get what my $type = shift; does at all, but I always see it. Do I need it?

shift with no arguments takes an argument off the head of @_ and assigns it to $type. The -> operator passes the invocant (left hand side) as the first argument to the subroutine. So this line gets the class name from the argument list. And, yes, you do need it.

.3. How does an array of inputs become the %params hash? my %params = @_;

Assignment into a hash is done in list context, with pairs of list items being grouped into as key/value pairs. So %foo = 1, 2, 3, 4;, creates a hash such that $foo{1} == 2 and $foo{3} == 4. This is typically done to create named parameters for a subroutine. If the sub is passed an odd number of arguments, an warning will be generated if warnings are enabled.

.4. What does 'my $self = {};` do?

This line creates an anonymous hash reference and assigns it to the lexically scoped variable $self. The hash reference will store the data for the object. Typically, the keys in the hash have a one-to-one mapping to the object attributes. So if class Foo has attributes 'size' and 'color', if you inspect the contents of a Foo object, you will see something like $foo = { size => 'm', color => 'black' };.

.5. Given $self->{'High'} = $params{'High'}; where does $params{'High'} come from?

This code relies on the arguments passed to new. If new was called like Foo->new( High => 46 ), then the hash created as per question 3 will have a value for the key High (46). In this case it is equivalent to saying $self->{High} = 46. But if the method is called like Foo->new() then no value will be available, and we have $self->{High} = undef.

.6. What does bless do?

bless takes a reference and associates with a particular package, so that you can use it to make method calls. With one argument, the reference is assoicated with the current package. With two arguments, the second argument specifies the package to associate the reference with. It is best to always use the two argument form, so that your constructors can be inherited by a sub class and still function properly.

Finally, I'll rewrite your hash based object accessor as I would write it using classical OO Perl.

package Foo;

use strict;
use warnings;
use Carp qw(croak);

sub new {
    my $class = shift;

    croak "Illegal parameter list has odd number of values" 
        if @_ % 2;

    my %params = @_;

    my $self = {};
    bless $self, $class;

    # This could be abstracted out into a method call if you 
    # expect to need to override this check.
    for my $required (qw{ name rank serial_number  });
        croak "Required parameter '$required' not passed to '$class' constructor"
            unless exists $params{$required};  
    }

    # initialize all attributes by passing arguments to accessor methods.
    for my $attrib ( keys %params ) {

        croak "Invalid parameter '$attrib' passed to '$class' constructor"
            unless $self->can( $attrib );

        $self->$attrib( $params{$attrib} );
    }

    return $self;
}
18
ответ дан 28 November 2019 в 04:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: