perl -e 'my $i=5; print(++$i + ++$i)' # почему тут 14, а не 13 ???
perl -e 'my $i=5; print(sub{++$i}->() + sub{++$i}->())' # тут все нормально - выдает 13
perl -e 'my $i=5; print( $i++ + $i++)' # и так нормально - выдает 11
Здесь хранятся разные советы, интересные куски кода, информация о полезных модулях ... и так далее :)
14 коммент.:
А что тут понимать?
В С подобное выполнить не пробовали?
my $i = 5;
$i = $i++;
print $i; # выводит 5 а не 6, как вроде должно было быть
Думаю что тут происходит так (дело в приоритетах)
сначала делается первый ++$i откуда получим $i=6 потом делатся второй раз ++$i откуда получим $i=7, а потом складываем два слагаемых в которых к этому времени уже $i=7
> zhdinar комментирует...
> my $i = 5;
> $i = $i++;
> print $i; # выводит 5 а не 6, как вроде должно было быть
Что-то вы путаете, уважаемый. $i++ - постфиксная форма записи, и наращивание переменной выполняется после выполнения прочих операций, т.е. в данном случае операции print.
> т.е. в данном случае операции print.
Пардон, попутал. Надо читать:"т.е. в данном случае операции сложения".
Переменной $i присваивается значение $i (т.е. 5), затем "старая" переменная увеличивается на 1, а потом уничтожается, т.к. над ней уже не производится никаких операций. Над "новой" $i больше никаких операций не производится, поэтому она и остаётся равной 5.
>А что тут понимать?
>В С подобное выполнить не пробовали?
Не пробовал
>Думаю что тут происходит так (дело в приоритетах)
Я с Вами полностью согласен, других вариантов особо и не вижу. Думаю, что это оптимизация для более быстрого выполнения. Perl не запоминает "6", а просто берет ее с переменной $i.
( Хотя по идее должно быть так:
Сначала вычисляется левый аргумент - инкремент на 1, а затем возврат "6". Потом вычисляется правый аргумент(полностью аналогично) - получаем 7. 6+7=13 )
Но меня смущает тот факт, что с таким примером:
perl -e 'my $i=5; print( $i++ + $i++)'
такого не происходит.
Когда Perl доходит до операции сложения, то $i уже равняется "6". Почему в данном случае сумма не равна 12?
Вот еще пару забавных примеров(с учетом вышесказанного тут все предсказуемо):
perl -e 'my $i=5; print( ${\ ("" . ++$i)} + ${\ ("" . ++$i)} )' # 13 (сохраняет вычисленный левый аргумент, как новую строку)
perl -e 'my $i=5; print( ${\ (++$i)} + ${\ ( ++$i)} )'# 14 (не сохраняет вычисленный левый аргумент)
Попробую на досуге сделать Tie-днутый скаляр и пологировать обращения.
Анонимный комментирует...
>"старая" переменная увеличивается на 1, а потом
> уничтожается, т.к ...
понимаю о чем вы говорите, позвольте высказать как я все это понимаю.
приведем соответствие:
$i - ячейка памяти
5 - одно из чисел, которыми мы орудуем (сохраняем в памяти $i, либо удаляем ) исходя из этого пошагово рассмотрим действия:
1) $i = 5; - положили в ячейку памяти $i число 5
2) $i = $i++ - два арифметических действия а именно..
2.1) $i = $i; - взяли из ячейки $i цифру 5 и положили ее обратно
2.2) $i++ - взяли число 5 из ячейки, увеличили на единицу, получилось 6, положили обратно, теперь в ячейке цифра 6.
по вашей логике получается, что в пункте 2.1 мы орудовали двумя ячейками с одинаковым именем и переложили цифру 5 из одной ячейки в другую
... буду очень признателен, если вы для меня проясните эту ситуацию
1) $i=5;
2) $i=$i++;
2.1) вычислили правый аргумент - равен 5.
поскольку используется постфиксный инкремент - сначала возвращается значение переменной, а затем инкрементируется.
2.2) происходит инкремент переменной $i. В ней теперь 6
2.3) переменной $i присваивается ранее вычисленный правый аргумент, который равен 5.
По сути $i=$i++; можно описать так:
$right_arg = $i; $i = $i + 1; $i =$right_arg
В общем, ответ есть в перлдок - "никогда так не пишите" :)
Auto-increment and Auto-decrement "++" and "--" work as in C. That is, if placed before a variable, they increment or decrement the variable by one before returning the value, and if placed after, increment or decrement after returning the value.
$i = 0; $j = 0;
print $i++; # prints 0
print ++$j; # prints 1
Note that just as in C, Perl doesn't define when the variable is incremented or decremented. You just know it will be done sometime before or after the value is returned. This also means that modifying a variable twice in the same statement will lead to undefined behaviour.
Avoid statements like:
$i = $i ++;
print ++ $i + $i ++;
Perl will not guarantee what the result of the above statements is.
ЗЫ: Ну и еще может кто не знает - автоинкремент работает и на символьных строках
$i="a"; $i++; print $i # выдаст "b"
>По сути $i=$i++; можно описать так:
>$right_arg = $i; $i = $i + 1; $i =$right_arg
Спасибо,пояснили все ясно и доходчиво, хотя я все-таки не согласен, в выражении $i = $i++; как ни крути cама $i должна увеличиться на 1, независимо от приоритета операции и использования временных значений
только что смотрел перлдок :), истина где-то рядом
Так понятное дело что нечего такое писать, перлдок как всегда прав :)
Погуглите "точки следования".
<Погуглите "точки следования".
Спасибо за наводку.
Отправить комментарий
Не забудьте добавить себя в постоянные читатели и включить уведомления о новых комментариях, либо воспользуйтесь RSS каналом ;)