Модераторы: korob2001, ginnie

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Объявление и инициализация в цикле, Объявление и инициализация в цикле 
V
    Опции темы
ginnie
Дата 20.3.2008, 14:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 38
Всего: 49



Уважаемые коллеги!
Извините за "детский" вопрос, но хочу для себя прояснить как работает объявление и инициализация внутри цикла:

Код

for $count (1..10) {
    my $test = 13 + $count;
    print $test;
}
 

На каждой итерации происходит только присвоение переменной $test нового значения, или что-то большее? Очень приветствуется ссылка на документацию!


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
GoDleSS
Дата 20.3.2008, 15:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



Для начала perldoc -f my

Функция my объявляет переменную локальной для текущего блока.
Таким образом переменная, описанная my внутри цикла будет каждый раз "создаваться" по новой, а старые участки памяти будут стираться, за исключением случаев, когда на них уже что-либо ссылается.

Таким образом код
Код

for $count (1..10) {
    my $test = 13 + $count;
    print $test;
}

выведет 14..23 

Это сообщение отредактировал(а) GoDleSS - 20.3.2008, 15:45
--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
amg
Дата 20.3.2008, 15:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



А вот такой дурацкий код что напечатает? Можете сказать, не проверяя? (Я бы не угадал smile )
Код

for $count (1..10) {
    $test = 13 + $count + my $test;
    print $test;
}

PM MAIL   Вверх
BlackLFL
Дата 20.3.2008, 16:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 263
Регистрация: 15.9.2005
Где: Москва

Репутация: 8
Всего: 12



такой код в обще не должен дать результат, т.к. переменная $test не объявлена до инициализации.
PM WWW   Вверх
KSURi
Дата 20.3.2008, 16:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 887
Регистрация: 8.6.2006
Где: Russia

Репутация: 20
Всего: 27



То, что написал GoDleSS - логично, я всегда так и считал. Но вот сейчас начал сомневаться:
Код

C:\>perl -MDevel::Peek -e"for(1..5){my$test=int rand time;Dump $test}"
SV = IV(0x18274dc) at 0x182428c
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 681182229
SV = IV(0x18274dc) at 0x182428c
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 172098990
SV = IV(0x18274dc) at 0x182428c
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 933110713
SV = IV(0x18274dc) at 0x182428c
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 884638863
SV = IV(0x18274dc) at 0x182428c
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 1151988534
C:\>

Меня смущает, что у всех $test один адрес в памяти. Если переменная каждый раз создается снова, то почему адрес всегда одинаковый?

Это сообщение отредактировал(а) KSURi - 20.3.2008, 16:08


--------------------
Died at Life.pl line 21
PM Jabber   Вверх
ginnie
Дата 20.3.2008, 16:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 38
Всего: 49



Уважаемый GoDleSS, на чем основана уверенность, что будет создаваться новая переменная? Спасибо за то, что навели на верную мысль!

код

Код

for my $count (1..10) {
    my $test = 13 + $count;
    print $test, ' ', \$test,"\n";
}


выводит

Код

14 SCALAR(0x804eac4)
15 SCALAR(0x804eac4)
16 SCALAR(0x804eac4)
17 SCALAR(0x804eac4)
18 SCALAR(0x804eac4)
19 SCALAR(0x804eac4)
20 SCALAR(0x804eac4)
21 SCALAR(0x804eac4)
22 SCALAR(0x804eac4)
23 SCALAR(0x804eac4)



--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
BlackLFL
Дата 20.3.2008, 16:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 263
Регистрация: 15.9.2005
Где: Москва

Репутация: 8
Всего: 12



2ginnie, не успел запостить, я тоже провел аналогичный тест
Код

for my $count (1..10) 
{
    my $test = 13 + $count;
    test( \$test );
}

print "\n";

for my $count (1..10) 
{
    my $test = 13 + $count;
    test( \$test );
}

sub test
{
    my $var = shift;
    
    print $var;
    print "\n";
}

Цитата

SCALAR(0x226f7c)
SCALAR(0x226f7c)
SCALAR(0x226f7c)
SCALAR(0x226f7c)
SCALAR(0x226f7c)
SCALAR(0x226f7c)
SCALAR(0x226f7c)
SCALAR(0x226f7c)
SCALAR(0x226f7c)
SCALAR(0x226f7c)

SCALAR(0x1aaf368)
SCALAR(0x1aaf368)
SCALAR(0x1aaf368)
SCALAR(0x1aaf368)
SCALAR(0x1aaf368)
SCALAR(0x1aaf368)
SCALAR(0x1aaf368)
SCALAR(0x1aaf368)
SCALAR(0x1aaf368)
SCALAR(0x1aaf368)


Это сообщение отредактировал(а) BlackLFL - 20.3.2008, 16:12
PM WWW   Вверх
ginnie
Дата 20.3.2008, 16:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 38
Всего: 49



BlackLFL, почему не объявлена? Какая часть присваивания выполняется сначала левая или правая?


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
BlackLFL
Дата 20.3.2008, 16:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 263
Регистрация: 15.9.2005
Где: Москва

Репутация: 8
Всего: 12



Цитата

BlackLFL, почему не объявлена? Какая часть присваивания выполняется сначала левая или правая? 


тут это не имеет значения, Perl все-равно выдаст ошибку 
Цитата

Global symbol "$test" requires explicit package name


Это сообщение отредактировал(а) BlackLFL - 20.3.2008, 16:15
PM WWW   Вверх
amg
Дата 20.3.2008, 16:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Цитата(BlackLFL @  20.3.2008,  16:14 Найти цитируемый пост)
тут это не имеет значения, Perl все-равно выдаст ошибку 
С use strict - безусловно. А без него?

PM MAIL   Вверх
BlackLFL
Дата 20.3.2008, 16:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 263
Регистрация: 15.9.2005
Где: Москва

Репутация: 8
Всего: 12



Цитата(amg @ 20.3.2008,  17:19)
Цитата(BlackLFL @  20.3.2008,  16:14 Найти цитируемый пост)
тут это не имеет значения, Perl все-равно выдаст ошибку 
С use strict - безусловно. А без него?

правый конечно
PM WWW   Вверх
amg
Дата 20.3.2008, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Что-то я понимаю, нифига не понимаю. И по поводу переменной с my в цикле (вроде, каждый раз должна новая пременная создаваться, по крайней мере, работает, как будто так оно и есть, но так ли на самом деле ?). И с тем своим дурацким кодом тоже не вполне ясно, в какой последовательности операции выполняются.

Добавлено через 4 минуты и 20 секунд
BlackLFL, но если сначала выполняется правая часть (я тоже в этом был уверен), то почему переменная в левой части оказывается неопределенной? 
PM MAIL   Вверх
BlackLFL
Дата 20.3.2008, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 263
Регистрация: 15.9.2005
Где: Москва

Репутация: 8
Всего: 12



amg, кстати да ... интересно получается ...

Добавлено @ 17:10
мне так кажется, что my имеет какое-то волшебное умение применять undef ... а сам интерпретатор, лишь "опирается" на my, для создания таблицы имен ...

Это сообщение отредактировал(а) BlackLFL - 20.3.2008, 17:10
PM WWW   Вверх
ginnie
Дата 20.3.2008, 17:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 38
Всего: 49



amg, похоже на то, что локальная переменная становится видна (кроме непосредственного присваивания) в коде только начиная со следующей команды (после ';') в коде программы.
Например, в коде
Код

if (my $test = rand() and $test++) {
    print $test, "\n";
}


получаем Global symbol "$test" requires explicit package name в строке с условием

По поводу цикла показателен следующий пример
Код

for my $count (1..10) {
    my $test;
    $test = $test // $count;
    print $test, ' ', \$test,"\n";
}


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


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
ginnie
Дата 20.3.2008, 18:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 38
Всего: 49



Дальнейшие исследования показали, что в коде 
Код

my $test = 0;
for my $count (1..10) {
    $test = 13 + $count + my $test;
    print $test // 'undef', "\n";
}
print $test, "\n";


получаем результат
Код

undef
undef
undef
undef
undef
undef
undef
undef
undef
undef
23


т.е. присваивание в цикле проиводится переменной $test, определенной выше цикла.



--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
GoDleSS
Дата 20.3.2008, 18:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



Цитата

Уважаемый GoDleSS, на чем основана уверенность, что будет создаваться новая переменная?

Сторонние мануалы, проверил,
Код

#!perl
$|=1;
END { sleep(10); }

&loopOut;

sub loopOut {
    for (1..10) {
        my $test = 1 + $_;
        testVar(\$test);
    }
}

sub testVar {
    my $var = shift;
    print "link $var\tvalue $$var\n";
}


Код

link SCALAR(0x18329d8)  value 2
link SCALAR(0x18329d8)  value 3
link SCALAR(0x18329d8)  value 4
link SCALAR(0x18329d8)  value 5
link SCALAR(0x18329d8)  value 6
link SCALAR(0x18329d8)  value 7
link SCALAR(0x18329d8)  value 8
link SCALAR(0x18329d8)  value 9
link SCALAR(0x18329d8)  value 10
link SCALAR(0x18329d8)  value 11


признаю свою неправоту по данному пункту smile
Не перевыделение, а перезаполнение одной и той же области памяти - явный плюс в сторону перлы!

Вообще исследование получается интересным, хоть и отрывает от работы )

Это сообщение отредактировал(а) GoDleSS - 20.3.2008, 18:25
--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
ginnie
Дата 20.3.2008, 18:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 38
Всего: 49



Уважаемые коллеги, спасибо за помощь!
Для себя из обсуждения вынес следующее:

1. Локальная переменная внутри цикла создается на первой итерации. На каждой итерации в этом месте ей присваивается значение undef.
2. В perlsub в разделе Private Variables via my() написано 
Код

The declared variable is not introduced (is not visible) until after the current statement.

что приводит к разным нетривиальным последствиям (примеры приведены выше).
3. При использовании переменной внутри цикла до строки объявления приводит к использованию одноименной переменной, определенной выше области видимости цикла на любой итерации.

Это сообщение отредактировал(а) ginnie - 20.3.2008, 18:31


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
GoDleSS
Дата 21.3.2008, 14:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



Еще одно маленькое исследование 
Код

#!perl
$|=1;
END { sleep(10); }

&loopOut;

{
my @data;

    sub loopOut {
        for (1..10) {
            my $test = 1 + $_;
            storeData(\$test);
        }
        &printResult;
    }

    sub storeData {
        $data[++$#data] = shift;
    }

    sub printResult {
        foreach (@data) {
            print "link $_\tvalue $$_\n";
        }
    }

}




link SCALAR(0x18329f0)  value 2
link SCALAR(0x226060)   value 3
link SCALAR(0x225e8c)   value 4
link SCALAR(0x1832984)  value 5
link SCALAR(0x1832b70)  value 6
link SCALAR(0x1832b88)  value 7
link SCALAR(0x1832ba0)  value 8
link SCALAR(0x1832bb8)  value 9
link SCALAR(0x1832bd0)  value 10
link SCALAR(0x1832be8)  value 11

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

Perl умный однако smile

Далее замечается один момент:
увеличение адреса статично - 24 байта/шаг
выделяется сегмент под одну переменную + под 1 элемент массива
и того получается, что перла изначально выделяет под скаляр 12 байт

Это сообщение отредактировал(а) GoDleSS - 21.3.2008, 14:30
--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
ginnie
Дата 21.3.2008, 14:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 38
Всего: 49



GoDleSS, спасибо за важное дополнение!

А вот за

Код

$data[++$#data] = shift;


надо по рукам надавать  smile 


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
GoDleSS
Дата 21.3.2008, 15:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



Цитата

А вот за
- // -
надо по рукам надавать 

Это почему же, позвольте полюбопытствовать? 0_о
Часто пользуюсь похожими конструкциями и не вижу в них ничего плохого.

--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
ginnie
Дата 21.3.2008, 15:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 38
Всего: 49



Нигде не встречал рекомендаций по добавлению нового элемента в массив путем инкремента номера последнего элемента этого массива:

Код

push(@array, $value); # стандартно
$array[$#array+1] = $value; # плохо
$array[++$#array] = $value; # ужасно :о)


Можно ссылку на документацию по поводу ++$#array?


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
GoDleSS
Дата 21.3.2008, 16:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



Цитата

Нигде не встречал рекомендаций по добавлению нового элемента в массив путем инкремента номера последнего элемента этого массива

Пока конструкция на ура, взял его из каких-то готовых решений очень давно
использую на ряду с push(@array, LIST); и не вижу явных минусов, за исключением разве что соображения: "Зачем понижать читабельность кода, используя и push, и ++$#array

Но это уже все слишком далеко от темы ;)
--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
ginnie
Дата 21.3.2008, 16:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 38
Всего: 49



GoDleSS, если не сложно, расскажите, как работает конструкция

Код

$array[++$#array] = $value;



--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
GoDleSS
Дата 21.3.2008, 16:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 11.2.2007
Где: Пироговский

Репутация: 2
Всего: 2



$#array содержит индекс последнего элемента массива
если мы говорим
$#array=-1;
все элементы удаляются (индекс всегда >=0), аналогично @array=();
если мы говорим
$#array++
индекс последнего элемента увеличивается на еденицу, но после передачи значения индекса, поэтому
$array[$#array++] = expr;
приведет к переопределению текущего последнего элемента и созданию нового со значением undef
выражение ++$#array увеличит индекс последнего с передачей индекса до выполнения, поэтому
$array[++$#array] = expr;
банальный аналог push(@array, expr); при условии, что expr - скаляр


Надеюсь, что более или менее доступно изложил мысль smile

Это сообщение отредактировал(а) GoDleSS - 21.3.2008, 16:21
--------------------
It's a nice day to die my friend!
PM MAIL WWW ICQ   Вверх
KSURi
Дата 21.3.2008, 17:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 887
Регистрация: 8.6.2006
Где: Russia

Репутация: 20
Всего: 27



Цитата(GoDleSS @  21.3.2008,  16:20 Найти цитируемый пост)
$#array=-1;

Я вообще думал, что $#arr - readonly oO
Спасибо, буду знать, хотя не знаю зачем)



--------------------
Died at Life.pl line 21
PM Jabber   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0690 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.