【问题标题】:Self-deleting array elements (once they become undefined)自删除数组元素(一旦它们变得未定义)
【发布时间】:2015-11-13 02:08:58
【问题描述】:

我有一个 Perl 脚本生成一组对对象的弱引用。一旦这些对象之一超出范围,数组中对它的引用将变为未定义。

ex(伪代码):

# Imagine an array of weak references to objects
my @array = ( $obj1_ref, $obj2_ref, $obj3_ref );

# Some other code here causes the last strong reference
# of $obj2_ref to go out of scope.

# We now have the following array
@array = ( $obj1_ref, undef, $obj3_ref )

有没有办法让未定义的引用在未定义后自动从数组中删除?

我想要@array = ($obj1_red, $obj3_ref )

编辑:

我尝试了这个解决方案,但它不起作用:

#!/usr/bin/perl
use strict;
use warnings;

{
    package Object;
    sub new { my $class = shift; bless({ @_ }, $class) }
}

{
    use Scalar::Util qw(weaken);
    use Data::Dumper;

    my $object = Object->new();

    my $array;
    $array = sub { \@_ }->( grep defined, @$array );

    {
        my $object = Object->new();
        @$array = ('test1', $object, 'test3');
        weaken($array->[1]);
        print Dumper($array);
    }

    print Dumper($array);

输出:

$VAR1 = [
          'test1',
          bless( {}, 'Object' ),
          'test3'
        ];
$VAR1 = [
          'test1',
          undef,
          'test3'
        ];

undef 不会自动从数组中删除。

我错过了什么吗?

编辑 2:

我还尝试在对象的 DESTROY 方法中从数组中删除未定义的值,但这似乎也不起作用。看来,由于该对象在技术上仍未“销毁”,因此仍会定义弱引用,直到 DESTROY 方法完成...

【问题讨论】:

  • 你的意思是my @array = ( ... )还是my $array = [ ... ]
  • 我的意思是(),我会更正它。抱歉,这只是一些快速编写的伪代码,更多的是为了理解这一点而不是语法正确。
  • 速写伪答案:清除对象析构函数中的列表。或者,使用一个对象而不是数组,它会在任何需要它的操作之前自行清理。
  • 您应该将其发布为真正的答案,析构函数方法听起来是个好主意。销毁对象后,我可以(可能)从数组中删除所有未定义的值。 :)
  • 关于“弱引用仍然被定义,直到 DESTROY 方法完成......”,np。搜索您对自己的引用而不是 undef。

标签: arrays perl oop weak-references


【解决方案1】:

不,没有,只是使用一个神奇的(例如绑定的)数组。

如果您引用的是数组而不是数组,则可以使用以下方法有效地过滤掉未定义的元素,而无需“强化”任何引用。

$array = sub { \@_ }->( grep defined, @$array );

事实上,这根本不会复制值。只有“C 指针”被复制。

【讨论】:

  • 这是否会在访问数组时运行 grep 命令?抱歉,我对代码参考及其工作原理不太熟悉。
  • 你可以在任何你想清除未定义值的地方运行命令,是的。
  • ThisSuitIsBlackNot 下面的评论怎么样,他声称在弱引用上使用 grep 会将其转换为强引用。这将是一个问题。
  • 他说的是对的,但和你说他说的不一样,所以我的回答和他的评论没有矛盾。
  • 我尝试了您的解决方案,但它似乎不起作用。请参阅上面的详细信息。
【解决方案2】:

Perl 不会自动为您执行此操作。你有几个选择。首先是每次使用时都要自己清洗:

my @clean = grep { defined $_ } @dirty;

或者您可以创建一个tie'd array 并将该功能添加到FETCH*POP 挂钩。

【讨论】:

  • grep 方法的问题是复制弱引用使其成为强引用。来自 Scalar::Util 文档:“这在其他情况下可能不太明显,例如grep(),例如,当通过对可能已经被破坏的对象的弱引用列表进行搜索时:@object = grep { defined } @object; 这确实会删除所有对已销毁对象的引用,但对对象的剩余引用将是强引用,导致剩余对象永远不会被销毁,因为现在在 @object 数组中始终存在对它们的强引用。"
  • @ThisSuitIsBlackNot 那么您是否必须将map 他们返回给weakrefs?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-28
  • 2019-01-22
  • 1970-01-01
  • 2015-03-05
  • 1970-01-01
相关资源
最近更新 更多