5

所以 perl5porters 正在讨论添加一个安全的解引用运算符,以允许类似的东西

$ceo_car_color = $company->ceo->car->color
    if  defined $company
    and defined $company->ceo
    and defined $company->ceo->car;

缩短为例如

$ceo_car_color = $company->>ceo->>car->>color;

哪里的$foo->>bar意思defined $foo ? $foo->bar : undef

问题:是否有一些模块或不显眼的 hack 让我得到这个运算符,或者具有视觉上令人愉悦的语法的类似行为?

为了您的享受,我将列出我能够提出的想法。

  1. 多重解除引用方法(看起来很难看)。

    sub multicall {
        my $instance = shift // return undef;
        for my $method (@_) {
            $instance = $instance->$method() // return undef;
        }
        return $instance;
    }
    
    $ceo_car_color = multicall($company, qw(ceo car color));
    
  2. 一个包装器,它变成undef一个代理对象(看起来更丑陋),它undef从所有函数调用中返回。

    { package Safe; sub AUTOLOAD { return undef } }
    sub safe { (shift) // bless {}, 'Safe' }
    
    $ceo_car_color = safe(safe(safe($company)->ceo)->car)->color;
    
  3. 由于我可以访问,和的实现ceo(),因此我考虑过直接从这些方法返回安全代理,但现有代码可能会中断:car()color()

    my $ceo = $company->ceo;
    my $car = $ceo->car if defined $ceo; # defined() breaks
    

    不幸的是,我没有看到任何perldoc overload关于重载安全代理的含义defined//安全代理的内容。

4

2 回答 2

3

也许这不是最有用的解决方案,但它是另一个 WTDI(nr. 1 的变体),它是List::Utilreduce的一个重要用例,这非常罕见。;)

代码

#!/usr/bin/env perl

use strict;
use warnings;
use feature     'say';
use List::Util  'reduce';

my $answer = 42;
sub new { bless \$answer }
sub foo { return shift }        # just chaining
sub bar { return undef }        # break the chain
sub baz { return ${shift()} }   # return the answer

sub multicall { reduce { our ($a, $b); $a and $a = $a->$b } @_ }

my $obj = main->new();
say $obj->multicall(qw(foo foo baz)) // 'undef!';
say $obj->multicall(qw(foo bar baz)) // 'undef!';

输出

42
undef!

笔记:

当然应该是

return unless defined $a;
$a = $a->$b;

而不是上面的较短$a and $a = $a->$b的,以正确使用已定义但错误的值,但我的意思是使用reduce

于 2012-09-27T10:01:12.010 回答
1

您可以使用eval

$ceo_car_color = eval { $company->ceo->car->color };

但它当然会捕获任何错误,而不仅仅是在undef.

于 2012-09-27T09:42:51.977 回答