在Perl中仅通过引用传递一些子例程参数

时间:2017-06-18 23:00:41

标签: perl pass-by-reference

我正在写一个带有许多参数的子程序。这些参数中的大多数是标准的按值传递排序,其中在子例程内对它们进行的更改在其外部并不重要。但其中一个是一个对象(祝福参考),我想对子程序之外的内容进行更改,如果它已经传入。如果它没有传入,我我希望实例化它并以与传入它相同的方式处理它(但最后将其返回)。

例如:

my $foo = Private::Foo->new();

# $foo->{'something'} eq 'old value'

Private::Foo->do_things('abc', 'xyz', $foo);

# $foo->{'something'} eq 'new value'

my $foo2 = Private::Foo->do_things('def');

# $foo2->{'something'} eq 'old value'
package Private::Foo;

# ...

sub do_things {
    my ($self, $arg1, $arg2, $foo) = @_;

    unless (defined $foo) {
         $foo = Private::Foo->new();
    }

    if ($arg1 eq 'abc') {
        $foo->{'something'} = 'new value';

        return;
    }

    return $foo;
}

我希望尽可能使用尽可能简洁的语法,并且我可以使用Perl v5.22及更高版本中提供的任何功能。 (我已经尝试使用refaliasing弄清楚如何执行此操作,但它并不是很干净。)

我错过了什么?

1 个答案:

答案 0 :(得分:0)

首先,子程序参数始终通过引用传递。

$ perl -e'sub f { $_[0] = "def"; }   my $x = "abc"; f($x); CORE::say $x;'
def

更重要的是,您的代码完全按照您的要求执行。

$ perl -e'
    {
        package Private::Foo;

        sub new { my $class = shift; bless({ something => "old_value" }, $class) }

        sub do_things {
            my ($self, $arg1, $arg2, $foo) = @_;

            unless (defined $foo) {
                 $foo = Private::Foo->new();
            }

            if ($arg1 eq "abc") {
                $foo->{something} = "new value";
                return;
            }

            return $foo;
        }
    }

    use feature qw( say );

    my $foo = Private::Foo->new();
    Private::Foo->do_things("abc", "xyz", $foo);
    say $foo->{something};

    my $foo2 = Private::Foo->do_things("def");
    say $foo2->{something};
'
new value
old_value

那就是说,你可以清理一下你的方法:

sub do_things {
    my ($class, $arg1, $arg2, $foo) = @_;

    $foo //= $class->new();

    if ($arg1 eq 'abc') {
        $foo->{something} = 'new value';
    }

    return $foo;
}

如果你清理了你的召唤惯例会更好。

Private::Foo->do_something($arg1, $arg2, $foo);

my $foo2 = Private::Foo->do_something($arg1, $arg2);

远不如

$foo->do_something($arg1, $arg2);

( my $foo2 = Private::Foo->new )->do_something($arg1, $arg2);