1. Perl / Говнокод #24884

    +1

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    #! /usr/bin/perl
    
    use strict;
    use warnings;
    
    my %h1 = (one => 1, two => 2);
    my %h2 = (three =>3 , four => 4);
    
    sub h_uno { \%h1 }
    
    sub h_multi {
        my %all = (%h1, %h2);
    
        \%all;
    }
    
    while (my ($k, $v) = each %{h_uno()}) {
        print "k=$k, v=$v\n";
    }
    
    # следующий цикл не завершится никогда
    #while (my ($k, $v) = each %{h_multi()}) {
    #    print "k=$k, $v=$v\n";
    #}

    Один из традиционных подколов собеседований на Perl вакансию.

    https://www.linux.org.ru/forum/job/14518840

    Запостил: Elvenfighter, 09 Октября 2018

    Комментарии (55) RSS

    • vanished
      Ответить
    • Perl не умер, он просто вышел покурить.
      Когда я работал на заводе -- мы юзали Perl.
      И язык этот во сто крат интересней всяких там педонов.

      Поясни, почему петля будет бесконечной?
      Ответить
    • Судя по сходству с "Bash", "Perl" — для админов.
      Ответить
    • vanished
      Ответить
    • vanished
      Ответить
    • Я слегка упростил твой пример, но смысл остался в том же.
      sub h_multi {
          print("Creating new hash\n");
          { "A", "B" }
      }
      
      # следующий цикл не завершится никогда
      while (my ($k, $v) = each %{&h_multi()}) {
          print "k=$k, $v=$v\n";
      }


      ``h_multi`` каждый раз создает новый хеш и возвращает на него ссылку.
      Почему ссылку?
      Мы обязаны это делать, так как вернуть из функции можно только скаляр (хеш вернуть нельзя, а ссылка на него это скаляр).

      ``each`` создает итератор и привязывает его к хешу. Это сильно отличается от того, как устроены итераторы в других языках, но похоже на то, как работает указатель внутри открытого файла.

      Просто представьте себе что внутри хеша есть указатель на ключ, следующий each сдвигает его на следующий ключ, и так до конца.

      Однако ``each`` вычисляет значение выражения каждый раз, когда дергается цикл.
      Соответственно, каждый раз вызывается ``h_multi``, который создает новый хеш с указателем на первый элемент.
      ``each`` его считывает, двигает дальше, получает новый хеш, его тоже читает, снова двигает, и так до бесконечности.

      Q: почему $k разные в разных итерациях?
      A: потому что hash не сортирован, это не массив
      Q: почему работает h_uno?
      A: потому что там возвращается ссылка на уже существующий хеш %h1, в ``h_multi`` создает новый хеш посредством слияния h1 и h2.
      Q: чтобля?
      A: в списковом контексте хеш выдает список ключ-значение. Несколько списков в списке сливаются (a,b,c,d) = ((a,b),c,d). Получившийся список при приведении к хешу заполняет его ключами из начениями (для примера выше a=>b, c=>d).

      Кокок, я прошел собеседование?
      Ответить
      • зы:
        ну и конечно же вот верная версия
        my %h1 = (one => 1, two => 2);
        my %h2 = (three =>3 , four => 4);
        
        sub h_uno { \%h1 }
        
        sub h_multi {
            my %all = (%h1, %h2);
        
            \%all;
        }
        
        while (my ($k, $v) = each %{h_uno()}) {
            print "k=$k, v=$v\n";
        }
        
        # следующий цикл завершится всегда
        my %fixed_by_petuh = %{h_multi()}; # вызовется один раз, сохраним хеш на стеке
        while (my ($k, $v) = each %fixed_by_petuh) {
           print "k=$k, $v=$v\n";
        }


        либо
        # следующий цикл завершится всегда
        my $fixed_by_petuh = h_multi();# сохраним ссылку на тот же хеш
        while (my ($k, $v) = each %$fixed_by_petuh) {
           print "k=$k, $v=$v\n";
        }
        Ответить
      • vanished
        Ответить
      • хороший язык, нет бойлерплейта
        Ответить

    Добавить комментарий