问题描述
我在问这个问题,因为我终于解决了一个问题,我一直在试图找到一种技术在很多情况下。我认为它非常整齐,所以我正在做一个Q-and-A。请参阅我是否可以使用 eval
,我只会这样做:
eval join(\\\
,map {
my $ v = $ valcashe {$ _};
sprintf('$ Text :: Wrap ::%s =%s',$ _
,(looks_like_number($ v)?$ v:''$ v')
)
}
);
Text :: Wrap :: wrap('','',$ text);
我甚至尝试过棘手,但似乎 local
将符号本地化为虚拟块,而不是物理块。所以这是行不通的:
ATTR_NAME:while(@attr_names){
没有严格的'refs';
my $ attr_name = shift;
my $ attr_name = shift @attr_names;
my $ attr_value = $ wrapped_attributes {$ attr_name};
my $ symb_path =Text \ :: Wrap\ :: $ attr_name;
本地$ {$ symb_path} = $ attr_value;
next ATTR_NAME if @attr_names;
Text :: Wrap :: wrap('','',$ text);
相同物理区块,以及我在设置之前和之后测试了包变量,他们甚至在循环中显示了它们的 时间的适当值。但测试表明,只有通过 last 变量的变量保留了对 wrap
调用的值。所以值只能保持本地化直到结束循环。
我认为解决方案非常简洁 - 即使奥秘perl magick。但最终结果是好的,因为这意味着我可以打包依赖于包范围变量的遗留代码,并确保所设置的值尽可能短。
Axeman,你这个白痴!软件包存储也是一个 hash !这样做:
local @Text :: Wrap :: {keys%wrapped_attributes}
= \(values% wrapped_attributes)
;
这包括以下内容:
- 它访问
Text :: Wrap
的符号表的数组切片,并返回指定的符号。
- 因为它是符号而不是标量,所以为了让perl知道正确的插槽,您必须分配引用。这对于数组和散列也是如此,但我们都知道它们的引用更常见。
\(...)
语法返回列表中每个项目的引用。
- 因为它是符号而不是标量,所以为了让perl知道正确的插槽,您必须分配引用。这对于数组和散列也是如此,但我们都知道它们的引用更常见。
因此,我们为%wrapped_attributes
中的每个键本地化每个变量,为其分配每个值的参考。
这很丑陋,每当我需要它时都很难将它移开 - 但通过它,我可以预先指定和延迟本地化以选择我可以摆放达米恩康威建议的铁丝网和危险标志的地方。
如果我要使用它,在我使用它的地方会很丑陋。
I'm asking this question because I finally solved a problem that I have been trying to find a technique for in a number of cases. I think it's pretty neat so I'm doing a Q-and-A on this.
See, if I could use eval
, I would just do this:
eval join( "\n"
, map {
my $v = $valcashe{$_};
sprintf( '$Text::Wrap::%s = %s', $_
, ( looks_like_number( $v ) ? $v : "'$v'" )
)
}
);
Text::Wrap::wrap( '', '', $text );
I even tried being tricky, but it seems that local
localizes the symbol to the virtual block, not the physical block. So this doesn't work:
ATTR_NAME: while ( @attr_names ) {
no strict 'refs';
my $attr_name = shift;
my $attr_name = shift @attr_names;
my $attr_value = $wrapped_attributes{$attr_name};
my $symb_path = "Text\::Wrap\::$attr_name";
local ${$symb_path} = $attr_value;
next ATTR_NAME if @attr_names;
Text::Wrap::wrap( '', '', $text );
}
Same physical block, and I tested the package variables before and after being set, and they even showed the proper value on their time through the loop. But testing showed that only the last variable passed through retained its value for the call to wrap
. So values only stayed localized until the end of the loop.
I think the solution is neat--even if arcane perl magick. But the end result is good because it means I can wrap legacy code that relies on package-scoped variables and be assured that the values set will be as short-lived as possible.
Axeman, you idiot! The package stash is a hash too! This works:
local @Text::Wrap::{ keys %wrapped_attributes }
= \( values %wrapped_attributes )
;
This does the following:
- It accesses the array slice of
Text::Wrap
's symbol table and returns the named symbols. - Because it's a symbol and not a scalar, in order for perl to know the correct slot, you have to assign references. This is true for arrays and hashes as well, but we all know that their references are more common.
- The
\( ... )
syntax passes back a reference for each item in the list.
So we localize each variable for each key in %wrapped_attributes
, and we assign it a reference for each value there.
It's ugly and arcane, and it's hard to move it out of the way each time I need it--but with it, I can pre-specify and delay the localization to select places where I can put up Damien Conway's suggested barbed wire and danger signs.
If I'm going to use it, it has to be just that ugly where I use it.
这篇关于如何在没有eval的情况下本地化一些原有的全局变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!