Страницы

Поиск по вопросам

пятница, 13 марта 2020 г.

Особенности возврата результата reverse из функции в Perl

#perl


Для предисловия делаем тестовый код, который переводит строку в верхний регистр,
немного комбинируя способы вызова и возврата из функций:

#!/usr/bin/perl
$str="Abc";
$s1=a($str);  $s2=b(a($str));  $s3=c($str);  $s4=b(c($str));
print "str=$str;  a()=$s1; b(a())=$s2; c()=$s3; b(c())=$s4\n";

sub b {  return $_[0];  }
sub a {  my($tmp)=$_[0];  return uc($tmp); }
sub c {  my($tmp)=$_[0];  return $tmp=uc($tmp);  }


Результат работы абсолютно предсказуемый:


  str=abc;  a()=ABC; b(a())=ABC; c()=ABC; b(c())=ABC


А теперь абсолютно то же самое сделаем, что бы развернуть строку задом наперед, используя
функцию reverse вместо uc:

#!/usr/bin/perl
$str="Abc";
$s1=a($str);  $s2=b(a($str));  $s3=c($str);  $s4=b(c($str));
print "str=$str;  a()=$s1; b(a())=$s2; c()=$s3; b(c())=$s4\n";

sub b { return $_[0]; }
sub a { my($tmp)=$_[0]; return reverse($tmp); }
sub c { my($tmp)=$_[0]; return $tmp=reverse($tmp); }


И тут мы получаем абсолютно неожиданный результат:


  str=Abc;  a()=cbA; b(a())=Abc; c()=cbA; b(c())=cbA


При передаче результата работы функции a, как параметра, в функцию b (которая просто
возвращает полученное значение) на выходе мы получаем не перевернутую строку. При этом,
практически идентичная функция c ведет себя так, как и было задумано. Собственно вот
это присваивание $tmp=reverse($tmp) при return я придумал, когда боролся с неожиданным
поведением с возвратом после reverse. Когда первый раз увидел это, ставил печать в
функцию b, у нее на входе именно такое значение как она и возвращает и которое собственно
напечатано в результате.

UPD: Проверил print b(reverse($str)); возвращает Abc !!!

Добавлю, что такой результат на Perl v5.12.4, на других версиях не проверял.

Вопрос: почему при возврате значения которое вернула reverse в случае прямого его
использования поведение ожидаемое, а при передаче этого значения как параметра в другую
функцию результат такой, как будто никакого reverse не было выполнено ? Глюк это или фича ?
    


Ответы

Ответ 1



Результат абсолютно ожидаемый и предсказуемый. Функция reverse работает по разному в скалярном и списочном контексте. В списочном контексте она разворачивает список, в скалярном - строку. А теперь вопрос. Если у нас есть список с одной строки, то что вернет для него reverse? Естественно, саму строку. При вызове b(a()) перл пытается понять контекст. Функция b возвращает просто свой первый аргумент, а получает на вход - список (она же функция, а аргументы у нее не были специфицированы). Поэтому, функция a должна возвращать список. Отсюда, return возвращает список. А это значит, что контест списочный. В списочном контексте аргумент считается списком и естественно строка стает списком с одним элементом. В функции c подобного не происходит - там явно виден скалярный контекст. P.S. код ужасен. Не пишите так. Как минимум используйте use strict; use warnings и my.

Комментариев нет:

Отправить комментарий