我可以请一个ArrayOutOfBoundsException吗?

时间:2016-01-27 03:46:25

标签: perl perl6

在Python中,如果使用越界键/索引索引集合结构,则会得到一记耳光:

>>> [1, 2, 3][9]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

这是一个例外;它派生自BaseException,如果不能处理它会崩溃我的程序,这几乎总是我想要的

Perl 5和6的列表索引似乎并不关心越界索引:

$ perl6
> my @l = (1..4);
[1 2 3 4]
> say @l[2];
3
> say @l[9];
(Any)
> print @l[9];                                                                                                          
Use of uninitialized value @l of type Any in string context
<snip>    
True
> my $x = @l[9]; # even assignment doesn't error! who decided this was okay!?
> say $x; print $x;
(Any)
Use of uninitialized value $x of type Any in string context
<snip>    

它在Perl 5中基本上是相同的,除了你没有得到返回值,但执行继续正常。

我不明白为什么越界访问应该无声。您获得该值的唯一警告可能是&#34;未初始化&#34; (但我们都知道它实际上意味着不存在)当你将它赋予某些功能时。

我能以某种方式解决这个问题吗?我可以实现我自己的post-circumfix索引操作符来覆盖在垃圾索引上死亡的默认操作符,但是没有办法区分未初始化的值和类型Any之间的区别。 I 可以看到的唯一方法是检查请求的索引是否在List.elems()范围内。

我可以使用什么(最好是简单,简洁,清晰,可读等)解决方案来解决这个问题?

在有人说'#34;是的之前,但变量未初始化,如my $x;!&#34;:在C中,如果你访问了你没有分配的内存,你会得到一个段错误;为什么我不具备这种安全性?

我已将此标记为Perl和Perl 6,因为虽然我学习Perl 6并且此问题的详细信息主要适用于6,但主要想法似乎是两者的共同方面。和6。

5 个答案:

答案 0 :(得分:11)

Perl 6具有整形数组,可在简单或多维数组上强制执行数组边界。

来自S09

my int @ints[4;2];          # Valid indices are 0..3 ; 0..1
my @calendar[12;31;24];     # Valid indices are 0..11 ; 0..30 ; 0..23

更多例子:

use v6;
# declare an array with four elements
my @l[4] = (1..4);
try { @l.push: 42}
say @l;
# [1 2 3 4]

这些可以是多维的

my @tic_tac_toe[3;3] = <x o x>, <o . o>, < x o x>;
@tic_tac_toe[1;1] = "x";      # ok
try @tic_tac_toe[3][3] = "o"; # illegal
say @tic_tac_toe;
# [[x o x] [o x o] [x o x]]

答案 1 :(得分:9)

这将做你想要的。

HashMap<String, Object> mo=new HashMap<String, Object>;

如果您想要堆栈跟踪,则必须运行my @a is default(Failure.new('IndexError')); @a[0] = 1; say @a[1]; say 'alive'; output: ===SORRY!=== IndexError 或使用perl6 --ll-exception创建自己的容器。 (这是一个错误,报告为:RT#127414

Proxy

哦,请不要听那些想要告诉你适应Perl 6的反对者.Perl 6的全部内容是你可以修补它并根据你的意愿弯曲它。

see: https://doc.perl6.org/type/Failure
see: https://doc.perl6.org/routine/is%20default
see: https://perl6advent.wordpress.com/2015/12/02/day-2-2-bind-or-2-bind/

有两种方法可以做到这一点。这是第三个。

class NonvivArray is Array {
    multi method AT-POS(NonvivArray:D: Int:D $pos) is raw {
        say 'foo';
        my $val = callsame;
        X::OutOfRange.new(got=>$pos, range=>0..self.elems-1).throw unless $val;
        $val;
    }

    multi method AT-POS(NonvivArray:D: int $ipos) is raw {
        say 'foo';
        my $val = callsame;
        X::OutOfRange.new(got=>$ipos, range=>0..self.elems-1).throw unless $val;
        $val;
    }
}

my NonvivArray $a;
$a.push: 1;
dd $a;
say $a[1];

有人可能会争辩说抛出的异常是LTA,或者说这实际上应该是特殊的。但是,它完成了OP要求的内容,而没有摆弄Rakudo实施的try { my Int:D @a; say @a[0]; CATCH { default { say .^name } } } # OUTPUT«X::Method::NotFound␤» 的实施细节。

答案 2 :(得分:5)

[既然你要求Perl5和Perl6答案,但你只得到一个Perl6答案,这里是一个Perl5答案。]

您可以编写一个操作检查程序,将索引操作替换为检查边界的操作(与no autovivification;替换解除引用操作的方式相同,使用不能自动生成的版本。)

答案 3 :(得分:2)

您可以受Acme::Array::MaxSize的启发 - 即您可以使用Tie::Array拦截数组操作。

答案 4 :(得分:-1)

  

这几乎总是我想要的。

请不要尝试根据您的想法调整语言,但要根据语言调整您的想法。如果您不愿意这样做,请使用符合您想法的其他语言。尝试在Perl中编写Java风格的代码是一个坏主意,就像在Java中编写Perl风格的代码一样。