我可以有一个 ArrayOutOfBoundsException 吗?
Can I please have an ArrayOutOfBoundsException?
在Python中,如果你索引一个集合结构有越界key/index,你会被打脸:
>>> [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 中基本上是一样的,除了你没有得到返回值,但执行继续正常。
我不明白为什么越界访问应该沉默。您得到该值的唯一警告可能是 "uninitialised"(但我们都知道这实际上意味着 不存在 )是当您将其赋予某些函数时。
我能以某种方式解决这个问题吗?我可以实现自己的 post-circumfix 索引运算符来覆盖死于垃圾索引的默认运算符,但是无法区分未初始化的值和类型 Any
之间的区别。 I 可以看到的唯一方法是检查请求的索引是否在 List.elems()
.
范围内
我可以使用什么(最好是最小的、简单的、干净的、可读的等)解决方案来解决这个问题?
在任何人说 "yes, but the variable is uninitialised, like my $x;
!" 之前:在 C 中,如果访问未分配的内存,则会出现段错误;为什么我不能有那种安全感?
我将此标记为 Perl 和 Perl 6,因为虽然我正在学习 Perl 6 并且这个问题的细节主要适用于 6,但主要思想似乎是 5 和 6 的共同方面.
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]
这些可以是multi-dimensional
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]]
which is almost always what I want.
请不要试图让语言适应你的想法,而是让你的想法适应语言。如果您不愿意这样做,请使用适合您想法的另一种语言。尝试用 Perl 编写 Java-style 代码与在 Java.
中编写 Perl-style 代码一样是个坏主意
[由于您要求同时提供 Perl5 和 Perl6 答案,但您只得到了 Perl6 答案,这里是 Perl5 答案。]
您可以编写一个操作检查器,将索引操作替换为检查边界的操作(就像 no autovivification;
将取消引用操作替换为不自动生成的版本一样。)
这会做你想做的事。
my @a is default(Failure.new('IndexError'));
@a[0] = 1;
say @a[1];
say 'alive';
output:
===SORRY!===
IndexError
如果你想要一个堆栈跟踪,你要么必须 运行 perl6 --ll-exception
要么用 Proxy
创建你自己的容器。 (这是一个错误,报告为:RT#127414)
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/
哦,请不要听信那些想要告诉你适应 Perl 6 的反对者。Perl 6 的全部要点在于你可以修补它并按照你的意愿弯曲它。
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];
有两种以上的方法可以做到这一点。这是第三个。
try {
my Int:D @a;
say @a[0];
CATCH { default { say .^name } }
}
# OUTPUT«X::Method::NotFound»
有人可能会争辩说抛出的异常是 LTA 或者这实际上应该是特殊情况。但是,它按照 OP 的要求进行操作,而没有摆弄 Rakudo 实施的 Array
的实施细节。
你可以从Acme::Array::MaxSize - i.e. you can use Tie::Array中得到启发来拦截数组操作。
在Python中,如果你索引一个集合结构有越界key/index,你会被打脸:
>>> [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 中基本上是一样的,除了你没有得到返回值,但执行继续正常。
我不明白为什么越界访问应该沉默。您得到该值的唯一警告可能是 "uninitialised"(但我们都知道这实际上意味着 不存在 )是当您将其赋予某些函数时。
我能以某种方式解决这个问题吗?我可以实现自己的 post-circumfix 索引运算符来覆盖死于垃圾索引的默认运算符,但是无法区分未初始化的值和类型 Any
之间的区别。 I 可以看到的唯一方法是检查请求的索引是否在 List.elems()
.
我可以使用什么(最好是最小的、简单的、干净的、可读的等)解决方案来解决这个问题?
在任何人说 "yes, but the variable is uninitialised, like my $x;
!" 之前:在 C 中,如果访问未分配的内存,则会出现段错误;为什么我不能有那种安全感?
我将此标记为 Perl 和 Perl 6,因为虽然我正在学习 Perl 6 并且这个问题的细节主要适用于 6,但主要思想似乎是 5 和 6 的共同方面.
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]
这些可以是multi-dimensional
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]]
which is almost always what I want.
请不要试图让语言适应你的想法,而是让你的想法适应语言。如果您不愿意这样做,请使用适合您想法的另一种语言。尝试用 Perl 编写 Java-style 代码与在 Java.
中编写 Perl-style 代码一样是个坏主意[由于您要求同时提供 Perl5 和 Perl6 答案,但您只得到了 Perl6 答案,这里是 Perl5 答案。]
您可以编写一个操作检查器,将索引操作替换为检查边界的操作(就像 no autovivification;
将取消引用操作替换为不自动生成的版本一样。)
这会做你想做的事。
my @a is default(Failure.new('IndexError'));
@a[0] = 1;
say @a[1];
say 'alive';
output:
===SORRY!===
IndexError
如果你想要一个堆栈跟踪,你要么必须 运行 perl6 --ll-exception
要么用 Proxy
创建你自己的容器。 (这是一个错误,报告为:RT#127414)
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/
哦,请不要听信那些想要告诉你适应 Perl 6 的反对者。Perl 6 的全部要点在于你可以修补它并按照你的意愿弯曲它。
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];
有两种以上的方法可以做到这一点。这是第三个。
try {
my Int:D @a;
say @a[0];
CATCH { default { say .^name } }
}
# OUTPUT«X::Method::NotFound»
有人可能会争辩说抛出的异常是 LTA 或者这实际上应该是特殊情况。但是,它按照 OP 的要求进行操作,而没有摆弄 Rakudo 实施的 Array
的实施细节。
你可以从Acme::Array::MaxSize - i.e. you can use Tie::Array中得到启发来拦截数组操作。