Почему я использовал бы Perl анонимные подпрограммы вместо именованной?

Сделайте GROUP BY. Используйте MAX() (например), чтобы выбрать ненулевые значения:

select id, max(c2), max(c3), max(c4)
from tablename
group by id
19
задан brian d foy 9 May 2009 в 19:45
поделиться

7 ответов

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

Последний пункт, вероятно, самый важный, потому что это часто самый неожиданный аспект именованных и анонимных подпрограмм в Perl. Пример:

sub outer
{
  my $a = 123;

  sub inner
  {
    print $a, "\n";
  }

  # At this point, $a is 123, so this call should always print 123, right?
  inner();

  $a = 456;
}

outer(); # prints 123
outer(); # prints 456! Surprise!

Но изменить «внутреннее» с именованной подпрограммы на ссылку на анонимную подпрограмму, и это работает гораздо менее удивительным образом:

sub outer
{
  my $a = 123;

  my $inner = sub
  {
    print $a, "\n";
  };

  # At this point, $a is 123, and since the anonymous subrotine 
  # whose reference is stored in $inner closes over $a in the 
  # "expected" way...
  $inner->();

  $a = 456;
}

# ...we see the "expected" results
outer(); # prints 123
outer(); # prints 123

(Конечно, у всех разные ожидания, поэтому «пугающие цитаты» вокруг «ожидается.»)

Вот пример использования в реальном коде (хотя следует отметить, что интерфейс File :: Find , как правило, считается плохим из-за использования глобальных переменных , не использование анонимных подпрограмм):

sub find_files
{
  my @files;

  my $wanted = sub
  { 
    if($something)
    {
      push @files, $File::Find::name;
    }
  };

  # The find() function called here is imported from File::Find
  find({ wanted => $wanted }, $directory);

  return @files;
}

Для передачи именованной подпрограммы в качестве значения параметра wanted потребуется загрязнение пространства имен подпрограммой, которую можно использовать только один раз, и определение именованной подпрограммы в подпрограмма find_files () будет демонстрировать «неожиданное» поведение, продемонстрированное ранее.

33
ответ дан 30 November 2019 в 02:03
поделиться

На ум приходят обратные вызовы и генераторы. Пример:

#!/usr/bin/perl

use strict;
use warnings;

sub generate_multiplier {
    my ($coef) = @_;

    return sub { 
        my ($val) = @_;
        $coef * $val;
    }
}

my $doubler = generate_multiplier(2);
my $tripler = generate_multiplier(3);

for my $i ( 1 .. 10 ) {
    printf "%4d%4d%4d\n", $i, $doubler->($i), $tripler->($i);
}

__END__

C:\Temp> v
    1   2   3
    2   4   6
    3   6   9
    4   8  12
    5  10  15
    6  12  18
    7  14  21
    8  16  24
    9  18  27
   10  20  30
15
ответ дан 30 November 2019 в 02:03
поделиться

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

my @sorted_array = sort { $a <=> $b } @array;

{$ a <=> $ b} представляет анонимную подпрограмму.

4
ответ дан 30 November 2019 в 02:03
поделиться

«Анонимные» подпрограммы действительно похожи на обычные именованные подпрограммы, за исключением того, что они не привязаны к имени в таблице символов.

sub Foo { stuff() }

BEGIN { *Foo = sub { stuff() } }  # essentially equivalent

Во втором случае подпрограмма «анонимная» создается и затем привязывается к имени «Foo» в текущем пространстве имен. Блок BEGIN делает это во время компиляции, так же, как обрабатывается именованная подпрограмма. (Это немного сложнее в том, что в первом случае ему присваивается имя, которое будет отображаться в трассировке стека.)

Анонимные подпрограммы полезны в любое время, когда вы хотите создать функцию во время выполнения. Это особенно хорошо для «замыканий» - функций, которые «запоминают» свой лексический контекст. Например, превращение списка в итератор:

use 5.010;
use strict;
use warnings;

sub make_iterator {
  my @list = @_;
  return sub { shift @list }; # new sub that 'remembers' @list
}

my $iter1 = make_iterator( 0 .. 10 ); 
my $iter2 = make_iterator( 'a' .. 'z' );

say $iter1->();  # '0'
say $iter1->();  # '1'
say $iter2->();  # 'a'

Чтобы узнать больше о том, почему анонимные подпрограммы полезны,

8
ответ дан 30 November 2019 в 02:03
поделиться

Во-первых: подпункт - это подпрограмма. my $ thing = sub ... является вложенной ссылкой, хранящейся в переменной.

Второе: есть небольшая разница в использовании:

use strict;
use warnings;

sub xx {
  my $zz=1;

   sub yy {
      print $zz;
   }
}


perl tmp.pl
Variable "$zz" will not stay shared at tmp.pl line 8.

Измените [ sub yy ...] на [ my $ yy = sub { ...] или [ local * yy = sub { ...], и жалоба исчезает.

Кроме того, если честно, ссылки на С подпрограммами проще работать, так же, как @ x = (1,2,3) против $ x = [1, 2, 3].

1
ответ дан 30 November 2019 в 02:03
поделиться

Вот пример из моей перезаписи версии Nasm version.pl

# jump table to subroutines / variables
my %jump = (
  id     => 'id',
  xid    => 'xid',
  hex_id => 'xid',

  h      => \&h,
  mac    => \&mac,
  sed    => \&sed,
  make   => \&make,
  nsis   => \&nsis,

  perl   => \&perl,
  dump   => \&perl,
  yaml   => \&yaml,
  yml    => \&yaml,
  json   => \&json,
  js     => \&json,

  help   => \&help,
  usage  => sub{
    require Pod::Usage;

    Pod::Usage::pod2usage(
      "run perldoc $0 or pod2text $0 for more information"
    );
  }
);

По сути, единственная причина, о которой я могу думать предназначен для обратных вызовов или для таблицы прыжков.

0
ответ дан 30 November 2019 в 02:03
поделиться

Я говорю об анонимных подпрограммах и о том, почему вы должны использовать их в Освоении Perl . Короче говоря, вы начинаете думать о поведении как о еще одной форме данных, точно так же, как вы думаете о строках или числах. Когда вам нравится эта идея, вы можете делать некоторые довольно удивительные вещи, потому что вы можете отложить принятие многих решений на очень поздний этап программы, и вам не нужно искажать дизайн кода, чтобы заранее справляться с каждой ситуацией, которая может появиться.

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

8
ответ дан 30 November 2019 в 02:03
поделиться
Другие вопросы по тегам:

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