Проверьте, если список пуст (Raku) - PullRequest
7 голосов
/ 26 марта 2020

FAQ: в Raku как проверить, пуст ли список? Существует ли больше идиоматических c способов, чем:

my @l = ();
say @l.elems == 0;
say @l == ();
say @l.Bool;

do c в списке рекомендует smartmatching

say $l ~~ ();
  1. Знаете ли вы другие способы?
  2. Можете ли вы объяснить, почему () === () не так, даже если "" === "" прав: я не совсем уверен в этом.

1 Ответ

10 голосов
/ 26 марта 2020

Из предложенных:

say @l.elems == 0;

Это хороший вариант, который следует избегать, поскольку он вызывает оценку всех элементов в отложенном списке (что может привести к исключению, если есть итераторы, помеченные как отложенные, поскольку альтернатива будет работать, пока не будет исчерпана вся память).

say @l == ();

Это работает, но имеет ту же проблему, что и выше. Оператор == равен цифре c, поэтому он будет приводить обе стороны к числу, а затем сравнивать их. Это также сводится к @l.elems (через. @l.Numeric). Вы могли бы написать эту форму дешевле как @l == 0, что является лучшим способом, если вы действительно хотите узнать, сколько всего элементов.

say @l.Bool;

Это лучше, потому что в ленивом списке это только вынуждает оценить не более одного элемента, чтобы ответить на вопрос. Однако на самом деле это обратное тому, что было задано: это True, если массив не пуст. Более естественно использовать префиксные операторы ? и !, например:

say ?@l; # is not empty
say !@l; # is empty

Хотя часто вам даже не нужно делать это , потому что такие вещи, как if и unless предоставляют логический контекст. Таким образом, можно написать:

if @l { }        # not empty
unless @l { }    # empty

Это, вероятно, лучшие способы.

Что касается других предложений:

say $l ~~ ();

Это хорошо, хотя, вероятно, медленнее, чем подход к булификации.

() === () неверно, даже если "" === "" верно

Это потому, что List является ссылочным типом, а не типом значения. Поскольку () каждый раз создает отдельный пустой список, они являются различными объектами и поэтому будут сравниваться как неидентичные. Вместо этого вы можете использовать eqv:

say () eqv ()    # True

Но не используйте это, чтобы проверить, является ли список пустым, потому что он, вероятно, чрезмерно указывает c. Например:

my @l; say @l eqv ();    # False
my @l; say @l eqv [];    # True

Это потому, что () имеет тип List, а my @l объявляет Array. В общем, вы не хотите заботиться о том, какой тип действительно существует.

Наконец, об этой строке:

my @l = ();

Назначение () бессмысленно; my @a уже создает пустое Array. Фактически, это достаточно распространенный запах кода, поэтому Comma IDE дает слабое предупреждение об этом:

Warning

...