Perl-如何使用子例程修改变量而不返回

Perl-如何使用子例程修改变量而不返回,perl,scope,subroutine,Perl,Scope,Subroutine,下一个代码用于获取文件路径并检查是否存在以及是否可以读取;否则,该值将切换为自定义值: use strict; use warnings; [...] sub checkFilePath{ my ($args) = @_; my $checkingPath = $args->{path}; my $checkingCustomPath = $args->{customPath}; my $canBeRead = 1; if ($chec

下一个代码用于获取文件路径并检查是否存在以及是否可以读取;否则,该值将切换为自定义值:

use strict;
use warnings;

[...]

sub checkFilePath{
    my ($args) = @_;

    my $checkingPath = $args->{path};
    my $checkingCustomPath = $args->{customPath};

    my $canBeRead = 1;
    if ($checkingPath) {
        if (!(-e "$checkingPath")) {
            print "[WARN] File $checkingPath doesn't exist.\n";
            $canBeRead = 0;
        } elsif (!(-f "$checkingPath")) {
            print "[WARN] $checkingPath is not a file.\n";
            $canBeRead = 0;
        } elsif (!(-r "$checkingPath")) {
            print "[WARN] File $checkingPath can't be read.\n";
            $canBeRead = 0;
        }
    } 
    if (!($canBeRead)) {
        # Testing custom regex file path
        # If doesn't exist, it will try to use custom file or the script will die
        die "[ERR] Custom file $checkingCustomPath doesn't exist\n"  if (!(-e $checkingCustomPath));
        die "[ERR] Custom file $checkingCustomPath is not a file\n"  if (!(-f $checkingCustomPath));
        die "[ERR] Custom file $checkingCustomPath cannot be read\n" if (!(-r $checkingCustomPath));
        return $checkingCustomPath;
    }
    return $checkingPath;
}

[...]

$logPath = checkFilePath({
    path => $logPath,
    customPath => $customLogPath
    });
我想知道是否有一种方法可以修改此代码,仅通过一个子程序调用来更新
$logPath
,如:

# $logPath = '/tmp/thisfiledoesntexist.txt'
checkFilePath({
        path => $logPath,
        customPath => $customLogPath
        });
# $logPath now has a valid filepath, which is the same as $customLogPath

如果将
$logPath
作为参数(或通过引用)传递给子例程,则可以更改它(通过修改
@
的正确元素(或修改引用的标量))。但您将其值复制到一个散列中,并传递对该散列的引用。充其量,您可以修改
$hash->{path}
,而不是
$logPath

sub fixFilePath {
    our $checkingPath; local *checkingPath = \shift;  # my \$checkingPath = \shift;
    my %args = @_;
    my $checkingCustomPath = $args{customPath};

    ...

    return if $canBeRead;

    ...

    $checkingPath = $checkingCustomPath;
}


fixFilePath($logPath,
    customPath => $customLogPath,
);

再仔细考虑一下,我决定提出一种不同的、不那么重复的、更清晰的方法:

use strict;
use warnings;

use autouse Carp => qw(croak);

print chooseFilePath('doesnot.exist', "$ENV{TEMP}/t.log"), "\n";

sub chooseFilePath {
    my $wantedPath = shift;
    my $defaultPath = shift;

    if (defined(my $reason = isBadFilePath($wantedPath))) {
        warn "[WARN] $reason.\n";
        if (defined($reason = isBadFilePath($defaultPath))) {
            die "[ERR] $reason.\n";
        }
        return $defaultPath;
    }

    return $wantedPath;
}

sub isBadFilePath {
    @_ or croak 'Need a path';

    my $path = shift;

    -e $path or return "File '$path' doesn't exist";
    -f _ or return "'$path' is not a file";
    -r _ or return "File '$path' can't be read";

    return;
}
输出:

C:\…\Temp>perl s.pl
[警告]文件“不存在。存在”不存在。
[错误]文件“C:\…\Temp/t.log”不存在。
C:\…\Temp>echo x>t.log
C:\…\Temp>perl s.pl
[警告]文件“不存在。存在”不存在。
C:\…\Temp/t.log

我不明白为什么这个答案被否决了,所以,+1来自我。我试图修改子例程末尾的
$hash->{path}
,但是当它结束时
customLogPath
没有改变。我编码的行是
{args->{customPath}='Testing';
。在子例程的内部和外部进行打印时,我得到不同的值“我试图在子例程的末尾修改
$hash->{path}
”,始终使用
使用strict;
!!
$hash
不存在。Re“我编码的行是
{args->{customPath}”='Testing';
,(我假设你的意思是
$args->{customPath}='Testing';
)总是使用
使用严格;
!!
$args
不存在。是的,我总是
在我的脚本上使用严格;
{args
是一个打字错误。我说的是
$args
,它存在于我原来的子例程(
中($args)=@;
)。这就是为什么我得到不同的值,我不明白为什么