【问题标题】:Perl - How to modify variables with subroutines without returnPerl - 如何使用子例程修改变量而不返回
【发布时间】:2018-01-25 16:32:58
【问题描述】:

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

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

【问题讨论】:

    标签: perl scope subroutine


    【解决方案1】:

    如果$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,
    );
    

    【讨论】:

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

    考虑到这一点,我决定提出一种不同的、更少重复的、而且 IMO 更清晰的方法:

    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
    [WARN] File 'doesnot.exist' doesn't exist.
    [ERR] File 'C:\...\Temp/t.log' doesn't exist.
    
    C:\...\Temp> echo x > t.log
    
    C:\...\Temp> perl s.pl
    [WARN] File 'doesnot.exist' doesn't exist.
    C:\...\Temp/t.log
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-24
      • 2016-10-20
      • 2015-01-19
      • 2013-02-15
      • 2014-07-04
      • 2014-07-02
      相关资源
      最近更新 更多