Is there a built-in function to clear all variable

2019-05-07 16:39发布

问题:

I'm looking for a way to clear all of my arrays in a Perl program.

Currently, I'm calling a subroutine that explicitly "resets" all arrays:

sub clear_arrays{(@array1,@array2,@array3)=((),(),());}

This forces me to find all the arrays in the program and literally reference them in the subroutine.

I've looked at the perldoc for reset, undef, and delete but couldn't interpret any of them in a way that would clear all arrays.

Is there a built-in function of Perl that can do this?

If not, is there a function that would return an array of all the array variables?

Ex:

my @prog_arrays = getarrays();
foreach(@prog_arrays){$_ = ();}

Where getarrays() might be a built-in Perl function that returns any/all initialized arrays in the program.


EDIT:
My particular situation involves only two global arrays that need to be reset. I broadened the question out of curiosity rather than necessity. Basically, my globals are @email_subject & @email_msg.

They have values pushed into them as the script progresses and data is gathered/analyzed. At the end of the script, the email message is sent, and the script may run again depending on the loop condition variable.

If it runs again, I need to clear these 2 globals so that they can be aggregated again during the next loop cycle. It's not killing me to clear these two arrays via literal reference, but I was just wondering if Perl already had some built-in function to clear the arrays without literally referencing them.

This may not be the best way to accomplish this, but it was the first intuitive option that I considered.

回答1:

As mentioned in other answers, your request speaks to a larger problem with the design of your program. You should either use lexicals that will fall out of scope, or closely manage all of your global arrays, and create a function that will clear them for you.

If you insist on bludgeoning every array in your namespace, at least take care and check to make sure you aren't writing over values that Perl may need:

for (keys %::) {  # for everything in `package main;`
    if (*{$::{$_}}{ARRAY}) {  # if there is an array in the slot
        # clear it unless it is a "special" array
        @{$::{$_}} = () unless /^(?:INC|ISA|EXPORT|EXPORT_OK|ARGV|_|\W)$/
    }
}

I would write it like this though:

my @global_arrays = \our (@foo, @bar, @baz);
sub clear_global_arrays {
    @$_ = () for @global_arrays
}

The effect is the same for the arrays in question, yet it does not run the risk of clobbering anything you did not intend to. You could even use my rather than our with the second example, whereas the first example requires the variables to be in the symbol table (aka defined with our).



回答2:

Don't use global arrays. It's as simple as that. Lexical arrays are limited to the scope where they are declared, and automatically start empty when you enter the scope.

If you must use globals, keeping track of them all in one place is a good idea anyway, so clearing them shouldn't be difficult.

Someone once posted an now-infamous tool to perlmonks to do what you want. The code was withdrawn after receiving much criticism of the whole idea; you can read some of the criticism here: http://www.perlmonks.org/index.pl?node_id=349496



回答3:

The fact that you want this screams "bad design" to me. However, on the assumption that you know exactly what you're doing with this radioactive chainsaw, you can accomplish it by accessing the global symbol table hash %:: or %main::. (The colons are part of the name.) This hash contains a mapping from every defined global symbol to a reference to its variable.

Something like this should suffice:

for my $ref (values %::) {
    @{$ref} = ();
}

Edited to remove the check against array references. All of the values are in fact typeglob references, so there's no need to check.