为什么我的一些范围是疯狂的?

Why are some of my ranges insane?

我尝试将范围的常见字符串描述(例如 1-9)解析为实际范围(例如 1 .. 9),但在包含两位数字时经常会得到奇怪的结果。例如,1-10 导致单个值 1 而不是十个值的列表,并且 11-20 给了我四个值 (11 10 21 20),其中一半不是在预期的数值范围内:

put get_range_for('1-9');
put get_range_for('1-10');
put get_range_for('11-20');

sub get_range_for ( $string ) {

    my ($start, $stop) = $string.split('-');

    my @values = ($start .. $stop).flat;

    return @values;
}

这会打印:

1 2 3 4 5 6 7 8 9
1
11 10 21 20

而不是预期的:

1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20

(我在发布这个问题之前就想通了,所以我在下面回答了。如果您想详细说明,请随时添加您自己的答案)。

split 的结果是 Str,因此您不小心创建了一个字符串范围而不是整数范围。在创建范围之前尝试将 $start$stop 转换为 Int

put get_range_for('1-9');
put get_range_for('1-10');
put get_range_for('11-20');

sub get_range_for ( $string ) {

    my ($start, $stop) = $string.split('-');

    my @values = ($start.Int .. $stop.Int).flat; # Simply added .Int here

    return @values;
}

满足您的期望:

1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20

问题确实是 .split returns Str 而不是 Int,原来的答案解决了。但是,我宁愿像这样实现我的 "get_range_for":

sub get_range_for($string) {
    Range.new( |$string.split("-")>>.Int )
}

这将 return 一个 Range 对象而不是 Array。但是对于迭代(这是您最有可能使用它的目的),这不会有任何区别。此外,对于更大的范围,"get_range_for" 的其他实现可能会占用大量内存,因为它将 Range 激活为 Array。这对“3-10”来说并不重要,但对“1-10000000”来说却很重要。

请注意,此实现使用 >>.Int 对从 .split 编辑的所有值 return 调用 Int 方法,然后使用 | 将它们作为单独的参数传递至 Range.new。如果 .split return 1 个值(如果它不能拆分)或超过 2 个值(如果字符串中出现多个连字符),这也会炸弹。