在Perl中,如何检测(绑定的)数组是否为空而不查看其大小?

时间:2021-05-03 00:04:26

I have been tinkering with the idea of hiding some implementation details of an IPC mechanism behind a tied array. The goal is to be able to do something like this on the server side:

我一直在修改在绑定数组后面隐藏IPC机制的一些实现细节的想法。目标是能够在服务器端执行类似的操作:

# setup code here. Client provides a function name, we find
# a function to deal with the request:
my $coderef = lookup($method);
local @_;
tie @_, 'My::IPC';
@ret = &$coderef;

The My::IPC class will then read serialized objects from a pipe/socket as needed (triggered through the SHIFT or FETCH method).

然后,My: IPC类将根据需要从管道/套接字中读取序列化的对象(通过SHIFT或FETCH方法触发)。

I would like to provide the authors of the server functions with ways to write his IPC-accessible functions in a way that he would write local functions, i.e.:

我想向服务器函数的作者提供编写ipc可访问函数的方法,使他能够编写本地函数,例如:

sub f1 {
    while (my $param = shift) {
        ...
    }
}

... as well as ...

…以及……

sub f2 {
    my ($foo, $bar, $baz, %flags) = @_;
    ...
}

f1 is intended to be able to deal with streams of data that may be larger than the amount of RAM available -- as long as each individual object fits into RAM after deserialization, everything is fine. f2 is intended for "simpler" functions where the argument list can be slurped into RAM.

f1可以处理可能大于可用RAM的数据流——只要每个单独的对象在反序列化后适合于RAM,一切都没问题。f2用于“更简单”的函数,在这些函数中,可以将参数列表拖放到RAM中。

To support both scenarios, the TIEARRAY constuctor and the SHIFT, FETCH, and FETCHSIZE methods need to be implemented. I consider that part solved. What bothers me is that I can't seem to find a way that lets me transmit undef values to f1 because even in list context, shift returns undef when used on an empty array. Something like

为了支持这两种场景,需要实现TIEARRAY constuctor和SHIFT、FETCH和FETCHSIZE方法。我认为那部分已经解决了。令我困扰的是,我似乎找不到一种方法可以将undef值传输到f1,因为即使在列表上下文中,当在一个空数组中使用shift时,也会返回undef。类似的

@params = splice @_, 0, 1;

might work here, but that does not exactly look like the obvious solution to users.

这在这里可能行得通,但对用户来说,这并不是显而易见的解决方案。

I could solve this by making a slight modification to f1 and by implementing FETCHSIZE in a way that it returns 1 as long as there is data available:

我可以对f1做一点修改,实现FETCHSIZE,只要有数据就返回1:

sub f3 {
    while (@_) {
        my $param = shift;
        ...
    }
}

But this would break f2 because only the first element would get assigned. Apparently, FETCHSIZE needs to provide an accurate value, but to get that accurate value, the entire array needs to be slurped into RAM -- which defeats the purpose of iterating over it.

但是这会破坏f2因为只有第一个元素会被赋值。显然,FETCHSIZE需要提供一个精确的值,但是为了获得这个精确的值,需要将整个数组读入RAM中——这就破坏了迭代它的目的。

Is there an elegant way to support both a "streaming" model (f1, f3) and a more simple function-call-like model (f2) with the same tied array implementation?

是否有一种优雅的方法来支持“流”模型(f1, f3)和更简单的类函数调用模型(f2),并使用相同的绑定数组实现?

1 个解决方案

#1


5  

Arrays have a length. If your code can't behave like an array, giving it the interface of an array isn't a good idea.

数组长度。如果代码不能像数组那样运行,那么给它一个数组的接口不是一个好主意。

You can get the underlying object using tied

您可以使用tie来获取底层对象

sub f1 {
   while ( my ($param) = tied(@_)->next() ) {
      ...
   }
}

sub f2 {
   my ($foo, $bar, $baz, %flags) = @_;
   ...
}

But avoiding tying something that isn't array-like is probably best.

但是避免绑一些不像array那样的东西可能是最好的。

sub f1 {
   my $o = shift;
   while ( my ($param) = $o->next ) {
      ...
   }
}

sub f2 {
   my ($foo, $bar, $baz, %flags) = shift->all;
   ...
}

Note that next is called in list context, so it has the option of returning an empty list in addition to returning undef, allowing the end of the iteration to be distinguishable from undef.

注意,next在list上下文中被调用,因此除了返回undef之外,它还可以返回一个空列表,从而允许迭代的结束与undef区分开来。

#1


5  

Arrays have a length. If your code can't behave like an array, giving it the interface of an array isn't a good idea.

数组长度。如果代码不能像数组那样运行,那么给它一个数组的接口不是一个好主意。

You can get the underlying object using tied

您可以使用tie来获取底层对象

sub f1 {
   while ( my ($param) = tied(@_)->next() ) {
      ...
   }
}

sub f2 {
   my ($foo, $bar, $baz, %flags) = @_;
   ...
}

But avoiding tying something that isn't array-like is probably best.

但是避免绑一些不像array那样的东西可能是最好的。

sub f1 {
   my $o = shift;
   while ( my ($param) = $o->next ) {
      ...
   }
}

sub f2 {
   my ($foo, $bar, $baz, %flags) = shift->all;
   ...
}

Note that next is called in list context, so it has the option of returning an empty list in addition to returning undef, allowing the end of the iteration to be distinguishable from undef.

注意,next在list上下文中被调用,因此除了返回undef之外,它还可以返回一个空列表,从而允许迭代的结束与undef区分开来。