Доступ к последнему элементу в Perl6

Может ли кто-нибудь объяснить, почему он обращается к последнему элементу в Perl 6

@array[*-1]  

и почему нам нужна звездочка *?

Не логичнее ли делать что-то вроде этого:

@array[-1] 

Ответ 1

Документация пользователя объясняет, что *-1 - это всего лишь объект кода, который также может быть записан как

-> $n { $n - 1 }

При передаче в [ ] он будет вызываться с размером массива в качестве аргумента для вычисления индекса.

Таким образом, вместо того, чтобы просто начать отсчет назад от конца массива, вы можете использовать его, например, для того, чтобы рассчитывать вперед из своего центра с помощью

@array[* div 2]     #=> middlemost element
@array[* div 2 + 1] #=> next element after the middlemost one

В соответствии с проектными документами причина запрета отрицательных индексов (которые могли быть приняты даже при вышеуказанном обобщении) заключается в следующем:

Семантика Perl 6 позволяет избежать индексирования разрывов (источник тонких ошибок времени выполнения) и обеспечивает порядковый доступ в обоих направлениях на обоих концах массива.

Ответ 2

Если вам не нравится какая-либо звезда, вы также можете:

my $last-elem = @array.tail;

или даже

my ($second-last, $last) = @array.tail(2);

Изменить: Конечно, существует также метод head:

my ($first, $second) = @array.head(2);

Ответ 3

Другие два ответы превосходны. Моя единственная причина для ответа заключалась в том, чтобы добавить немного больше объяснений о синтаксисе индексирования Whatever Star *.

Эквивалент синтаксиса Perl 6 @array[*-1] в Perl 5 будет $array[ scalar @array - 1]. В Perl 5 в скалярном контексте массив возвращает количество элементов, которые он содержит, поэтому scalar @array дает длину массива. Вычитание одного из них дает вам последний индекс массива.

Так как в Perl 6 индексы могут быть ограничены, чтобы никогда не быть отрицательными, если они отрицательны, то они определенно выходят за допустимые пределы. Но в Perl 5 отрицательный индекс может быть или не быть "вне диапазона". Если он выходит за пределы допустимого диапазона, тогда он дает только значение undefined, которое нелегко отличить от простого значения undefined в элементе.

Например, код Perl 5:

use v5.10;
use strict;
use warnings;
my @array = ('a', undef, 'c');

say $array[-1]; # 'c'
say $array[-2]; # undefined
say $array[-3]; # 'a'
say $array[-4]; # out of range

say "======= FINISHED =======";

приводит к двум почти одинаковым предупреждениям, но все еще заканчивается:

c
Use of uninitialized value $array[-2] in say at array.pl line 7.

a
Use of uninitialized value in say at array.pl line 9.

======= FINISHED =======

Но код Perl 6

use v6;
my @array = 'a', Any, 'c';

put @array[*-1]; # evaluated as @array[2] or 'c'
put @array[*-2]; # evaluated as @array[1] or Any (i.e. undefined)
put @array[*-3]; # evaluated as @array[0] or 'a'
put @array[*-4]; # evaluated as @array[-1], which is a syntax error

put "======= FINISHED =======";

также будет предупреждать о используемом значении undefined, но он не работает при использовании индекса, который выходит меньше 0:

c
Use of uninitialized value @array of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful.
  in block <unit> at array.p6 line 5

a
Effective index out of range. Is: -1, should be in 0..Inf
  in block <unit> at array.p6 line 7

Actually thrown at:
  in block <unit> at array.p6 line 7

Таким образом, ваш код Perl 6 может быть более надежным, если не дать отрицательных индексов, но вы все равно можете индексировать его с конца, используя синтаксис Whatever Star.

последнее слово совета

Если вам нужны только последние несколько элементов массива, я бы рекомендовал использовать метод tail, упомянутый в mscha answer. @array.tail(3) гораздо более понятен, чем @array[*-3 .. *-1].