IPC::Shareable 变量,“不能使用字符串...作为 SCALAR ref..”和内存地址
Posted
技术标签:
【中文标题】IPC::Shareable 变量,“不能使用字符串...作为 SCALAR ref..”和内存地址【英文标题】:IPC::Shareable variables, "Can't use string ... as a SCALAR ref.." and memory address 【发布时间】:2012-05-19 19:57:47 【问题描述】:请注意以下最小工作示例:
use warnings;
use strict;
use IPC::Shareable;
use Data::Printer;
IPC::Shareable->clean_up;
my $sharevar1 = "a";
my $sharevar2;
print "A: $sharevar1 $sharevar2\n";
p($sharevar1);
p($sharevar2);
my $glue1 = 'glu1';
my $glue2 = 'glu2';
my %options = (
create => 1, #'yes',
exclusive => 0,
mode => 0644, #0644,
destroy => 1, # 'yes',
);
my $sharevar_handle1 = tie $sharevar1, 'IPC::Shareable', $glue1 , \%options ; #
print "B1: $sharevar1 $sharevar2 - $sharevar_handle1\n";
my $sharevar_handle2 = tie $sharevar2, 'IPC::Shareable', $glue2 , \%options ; #
print "B2: $sharevar1 $sharevar2 - $sharevar_handle2\n";
p($sharevar1);
p($sharevar2);
$sharevar1 = "b";
#~ $sharevar1 = "AOE" . \$sharevar2;
$sharevar2 = 20;
print "C: ";
print "- $sharevar1 $sharevar2\n";
p($sharevar1);
p($sharevar2);
当我运行它时,我得到如下输出 - 这是预期的:
Use of uninitialized value $sharevar2 in concatenation (.) or string at tt.pl line 13.
A: a
"a"
undef
Use of uninitialized value $sharevar1 in concatenation (.) or string at tt.pl line 30.
Use of uninitialized value $sharevar2 in concatenation (.) or string at tt.pl line 30.
B1: - IPC::Shareable=HASH(0xa1dc1b8)
Use of uninitialized value $sharevar1 in concatenation (.) or string at tt.pl line 34.
Use of uninitialized value $sharevar2 in concatenation (.) or string at tt.pl line 34.
B2: - IPC::Shareable=HASH(0xa215b10)
undef (tied to IPC::Shareable)
undef (tied to IPC::Shareable)
C: - b 20
"b" (tied to IPC::Shareable)
20 (tied to IPC::Shareable)
但是,如果现在我尝试取消注释“$sharevar1 = "AOE" . \$sharevar2;
”行,同时注释掉上面的“$sharevar1 = "b";
”;那么我得到的输出几乎是相同的,除了最后:
...
B2: - IPC::Shareable=HASH(0x852fb20)
undef (tied to IPC::Shareable)
undef (tied to IPC::Shareable)
Can't use string ("AOESCALAR(0x836bf88)") as a SCALAR ref while "strict refs" in use at /usr/local/share/perl/5.10.1/IPC/Shareable.pm line 741.
C: $
现在,问题是这个“不能使用字符串...”实际上会导致崩溃...显然,如果 tie
d 变量曾经通过 \
获得引用,它会得到一个类似的值SCALAR(0x836bf88)
作为一个字符串,显然后来被 Perl 解释为一个地址...?!
我认为在这种情况下 Perl 会匹配字符串的起始部分 (SCALAR(...
) - 所以我试图通过在字符串 "AOE" 前面添加字符串来作弊 - 但奇怪的是,Perl 仍然注意到 (好像它正在为“0x withing parenthesis”寻找一些正则表达式,有点匹配):“不能使用字符串(“AOESCALAR(0x836bf88)”)作为SCALAR ref”......
我的问题是 - 我对 Perl 和 IPC::Shareable 如何解释地址(否则存储为“字符串”)正确的推理(不,请参阅下面的编辑;是的,请参阅post);不管是不是,我将如何将地址存储到 IPC::Shareable 中?
非常感谢您的任何回答, 干杯!
编辑:嗯,显然,打印包含字符串地址的字符串变量通常都可以正常工作 - 所以这个问题是 IPC::Shareable 特定的,我猜:
DB<1> $ttt = "aa"
DB<2> p $ttt
aa
DB<3> $eee = \$ttt
DB<4> p $eee
SCALAR(0xa382668)
DB<5> $eee = "erw".\$ttt
DB<6> p $eee
erwSCALAR(0xa382668)
DB<7> q
【问题讨论】:
【参考方案1】:如果您升级到IPC::Shareable
的最新版本 (0.60),我可以为您提供更好的帮助。我目前无法使用 Unix 机器来尝试此操作,但当前版本的第 741 行没有任何意义。
您应该知道,当您处理绑定变量时,您只是在与一个看起来像 Perl 变量的标准 API 交互。因此,在写 $sharevar1 = "AOE" . \$sharevar2
时,您实际上是在调用 IPC::Shareable::STORE($sharevar1, "AOE" . \$sharevar2)
,它几乎可以做它想做的事情。
我在模块中看到的是检查要分配的值(给绑定的标量)是否为参考值的代码,如果是,则将其绑定到 IPC::Shareable
(如果尚未绑定)。取消引用值时使用的类型是通过检查字符串化引用与/SCALAR/
等建立的,尽管我不知道它如何应用于您所看到的行为(我希望字符串'AOESCALAR(0x836bf88)'
被识别为不是参考,因此不受正则表达式检查)我相信它是有贡献的。也许这是我的版本中已修复的问题?
这种方法有很大的错误空间,尤其是与其他类相关的变量会完全抛弃整个事情。我建议你升级,看看最新版本是否支持你想做的事情。
请记住,这与核心 Perl 无关,而与模块不完全模拟 Perl 标量的接口有关。
【讨论】:
嗨@Borodin,感谢您的回答!我试过更新,perl
说:IPC::Shareable is up to date (0.6).
我已经更新了my post;我可以确认,只要不存在大写“SCALAR
”,就可以打印变量(即使是小写的“scalar
”);我也希望“被认为不是参考”,但显然不是这样,至少在我的 Ubuntu 机器上是这样。再次非常感谢 - 干杯!【参考方案2】:
好吧,原来我错了:)
事实证明,这个问题 - 毕竟 - 与字符串解析有关;即检查大写的关键字SCALAR
;这是OP中代码的相应更改部分:
p($sharevar1);
p($sharevar2);
#~ $sharevar1 = "b";
#~ $sharevar1 = substr "AOE" . \$sharevar2, 2, 7; # Can't use string ("ESCALAR") as a SCALAR ref
#~ $sharevar1 = substr "AOE" . \$sharevar2, 5, 10; # "ALAR(0x878", passes OK
$sharevar1 = lc \$sharevar2; # lowercase works too
$sharevar2 = 20;
print "C: ";
print "- $sharevar1 $sharevar2\n";
p($sharevar1);
p($sharevar2);
请注意,只要您有SCALAR
,即使您没有地址数字(如“ESCALAR”),也会引发严格使用错误。
但是,如果关键字SCALAR
不完整存在——即使它是小写的——那么错误就会消失;现在是终端日志的结尾:
...
B2: - IPC::Shareable=HASH(0x9ca2e58)
undef (tied to IPC::Shareable)
undef (tied to IPC::Shareable)
C: - scalar(0x9adef88) 20
"scalar(0x9adef88)" (tied to IPC::Shareable)
20 (tied to IPC::Shareable)
嗯,希望就是这样 - 但由于我还不太了解这种机制,欢迎任何更好的澄清, 干杯!
编辑:刚刚发现另一件事;有时你可能会这样做:
my $sharevar2;
my $sharevar_handle2 = tie $sharevar2, 'IPC::Shareable', $glue2 , \%options ; #
print($sharevar2);
我刚刚注意到有时(但并非总是如此,也不能真正说出何时); tie
而不是 'undef',会将 $sharevar2
变量设置为“SCALAR()”或“ARRAY()”之类的东西——在这种情况下,print($sharevar2);
语句将失败。
您不能以其他方式进行调试,但要在 $sharevar2
上使用 Data::Printer
的 p()
(因为无论如何尝试打印都会失败) - 而是在 $sharevar_handle2
上使用:
my $sharevar2;
my $sharevar_handle2 = tie $sharevar2, 'IPC::Shareable', $glue2 , \%options ; #
print "2 "; p($sharevar_handle2);
...然后输出可能是这样的:
...
2 IPC::Shareable
Parents Exporter
Linear @ISA IPC::Shareable, Exporter
public methods (31) : ....
private methods (11) : ....
internals:
_data \ "ARRAY(0xa21e788)",
_iterating "",
...
在这种情况下,您确定$sharevar2
设置为“ARRAY(0xa21e788)”,因此当尝试print
时总是会失败。请注意,这样的事情可能是由于有一个命令将$sharevar2
分配给一个引用(即= \$somevar;
)在代码中很晚;这种因果关系可能并不总是显而易见的。
对于临时修复,只需在 tie
之后将“行为不端”变量设置为 undef
- 这样可以更轻松地跟踪分配给引用的位置:
my $sharevar2;
my $sharevar_handle2 = tie $sharevar2, 'IPC::Shareable', $glue2 , \%options ;
# if here $sharevar2 somehow becomes "ARRAY(0x88417c8)" instead of undef; reset
print "1 "; p($sharevar_handle2); # would show "ARRAY(0x88417c8)"
$sharevar2 = undef;
print "2 "; p($refvarstr_handle); # should show undef
p($sharevar2); # should not crash, cause it's now ARRAY anymore, but undef
还相关:can't use string as a SCALAR ref while strict refs - perlmonks.org
【讨论】:
以上是关于IPC::Shareable 变量,“不能使用字符串...作为 SCALAR ref..”和内存地址的主要内容,如果未能解决你的问题,请参考以下文章