Кто-нибудь может объяснить мне это исключение только для чтения? - PullRequest
5 голосов
/ 26 июня 2010

Ниже мой код (не беспокойтесь, в верхней части модуля есть USUW)

Я проверяю, является ли ссылка на массив доступной только для чтения, и если это так, то я копирую ее в другую ссылку на массив. Тесты показывают, что массив не только для чтения, но при запуске он завершается с этой ошибкой. (Для тех из вас, кто не знаком со мной или Smart::Comments - эти ### Smart::Comments.)

### readonly( $arg_ref ) : readonly( $arg_ref )
### readonly( @$arg_ref ) : readonly( @$arg_ref )
my @ro = map { readonly( $_ ) } @$arg_ref;
### @ro
if ( readonly $arg_ref ) {
    $arg_ref = [ @$arg_ref ];
}
return map { my $val = shift @$arg_ref;
             $_ => $val 
            } @_ 
            ;

Это вывод, который я получаю:

### readonly( $arg_ref ) : 0
### readonly( @$arg_ref ) : 0

### @ro: [
###        0,
###        0,
###        0,
###        0,
###        0
###      ]

Но вот ошибка:

Modification of a read-only value attempted at ....pm line 247.

(247:

return map { my $val = shift @$arg_ref;
* * Тысяча двадцать-одина)

Кто-нибудь знаком с этой проблемой? Мы работаем с Perl 5.8.7. Есть идеи, как это решить?

Ответы [ 4 ]

2 голосов
/ 26 июня 2010

Если ссылка из DBI::fetchrow_arrayref возвращается только для чтения, попытка перезаписать ее не поможет: ссылка только для чтения, а не вещь ( т.е. , массив со значениями столбцов).

Сделайте свою собственную копию прямо на источнике, если вам нужны деструктивные обновления, например ,

my $arg_ref = [ $sth->fetchrow_array ];
1 голос
/ 26 июня 2010

Я думаю, я понял это. Роберт П. был прав, но он получил только половину ответа: Readonly и readonly делают разные вещи, хотя они должны делать то же самое, факт, что они этого не делают, является ошибкой. Я постараюсь объяснить, что происходит.

Readonly имеет две реализации для скаляров: одна ( Readonly :: XS ), основанная на флаге SvREADONLY, и одна (Readonly :: Scalar), основанная на связях, эмулирующих * 1009. * флаг.

readonly также имеет две реализации: одну в Perl (которая выполняет самоназначение и проверяет, вызывает ли она исключение) и одну в XS (опять же на основе флага SvREADONLY).

Существует 4 возможных комбинации, и, к сожалению, наиболее распространенная (только perl Readonly и XS readonly) является единственной, которая не работает так, как рекламируется.

Вот суть: sub Readonly::Readonly на самом деле вообще не использует Readonly::XS, только sub Readonly::Scalar. Это, вероятно, ошибка . readonly правильно сообщает, что переменная не является переменной только для чтения: ее только для чтения имитирует связь.

Это Readonly, здесь вина, ИМО, она должна делать правильные вещи, когда может, и документировать, когда не может. Прямо сейчас это не делает ни одного из тех.

1 голос
/ 26 июня 2010

Только для чтения и только для чтения.(Обратите внимание на заглавную R и строчную букву r. ;-))

См. Документацию Scalar :: Util , почему это так:

только для чтения SCALAR

Возвращает true, если SCALAR доступен только для чтения.

sub foo { readonly($_[0]) }
$readonly = foo($bar);              # false
$readonly = foo(0);                 # true

Это больше относится к псевдонимам (таким, которые передаются через циклы foreach или в @_, а не в модуль Readonly.

0 голосов
/ 26 июня 2010

Не похоже, что результат Scalar :: Util :: readonly может быть доверенным , как вы хотите использовать Свидетель:

perl -MScalar::Util=readonly -MReadonly -wle'
    Readonly my $arg_ref => [ qw(a b c)];
    print readonly $arg_ref;
    $arg_ref = 1;'

печать:

0
 Modification of a read-only value attempted at -e line 1.

(протестировано в perl5.8.8 с Readonly 1.03, Scalar :: Util 1.23)

...