#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.
Комментариев нет:
Отправить комментарий