println中链迭代器之间的不同行为!并从变量

时间:2017-06-17 05:26:54

标签: rust

为什么println!内联代码在这些示例中起作用而不是可变变量?

我预定了一些常量:

static ASCII_LOWERCASE: [char; 26] = [
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
];
static ASCII_UPPERCASE: [char; 26] = [
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
];
static ASCII_NUMERIC: [char; 10] = [
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
];
static ASCII_SYMBOLS: [char; 33] = [
    '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-',
    '_', '+', '=', '~', '`', '[', ']', '{', '}', '|', '\\',
    ':', ';', '"', '\'', '<', '>', ',', '.', '?', '/', ' ',
];

这适用于打印95个字符:

fn main() {
    for x in 0..95 {
        println!(
            "{}",
            ASCII_LOWERCASE
                .into_iter()
                .chain(ASCII_UPPERCASE.into_iter().chain(
                    ASCII_NUMERIC.into_iter().chain(
                        ASCII_SYMBOLS.into_iter(),
                    ),
                ))
                .nth(x)
                .unwrap()
        );
    }
}

这只打印13个字符和恐慌:

fn main() {
    let mut ascii = ASCII_LOWERCASE.into_iter().chain(
        ASCII_UPPERCASE.into_iter().chain(
            ASCII_NUMERIC.into_iter().chain(
                ASCII_SYMBOLS.into_iter(),
            ),
        ),
    );

    for x in 0..95 {
        println!("{}", ascii.nth(x).unwrap());
    }
}

输出失败:

a
c
f
j
o
u
B
J
S
2
$
`
,
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', /checkout/src/libcore/option.rs:335
note: Run with `RUST_BACKTRACE=1` for a backtrace.

即使在同一个迭代器上调用相同的方法,失败的结果也会跳过大多数字符。为什么这样做?

为了让它以我想要的方式工作:

fn main() {
    let ascii: Vec<&char> = ASCII_LOWERCASE
        .into_iter()
        .chain(ASCII_UPPERCASE.into_iter().chain(
            ASCII_NUMERIC.into_iter().chain(
                ASCII_SYMBOLS.into_iter(),
            ),
        ))
        .collect();

    for x in 0..95 {
        println!("{}", ascii[x]);
    }
}

为什么失败的版本表现不同?

2 个答案:

答案 0 :(得分:3)

这实际上是迭代器集合之间的区别。

迭代器将迭代一系列元素,永远不会产生相同的元素两次(尽管它可能产生相同的元素)。

集合是惰性的,只要您通过引用迭代,就可以多次迭代(使用into_iter通常会使用集合,清空它)。

这意味着:

fn main() {
    for x in 0..95 {
        println!(
            "{}",
            ASCII_LOWERCASE
                .into_iter()
                .chain(ASCII_UPPERCASE.into_iter().chain(
                    ASCII_NUMERIC.into_iter().chain(
                        ASCII_SYMBOLS.into_iter(),
                    ),
                ))
                .nth(x)
                .unwrap()
        );
    }
}

将95次创建一个迭代器链并到达x元素。这具有复杂性 O(N 2

另一方面:

fn main() {
    let mut ascii = ASCII_LOWERCASE.into_iter().chain(
        ASCII_UPPERCASE.into_iter().chain(
            ASCII_NUMERIC.into_iter().chain(
                ASCII_SYMBOLS.into_iter(),
            ),
        ),
    );

    for x in 0..95 {
        println!("{}", ascii.nth(x).unwrap());
    }
}

将创建一个迭代器,然后请求第0个元素,然后是第一个剩余的元素,然后是第二个剩余的元素。

线索在mut关键字中:每次调用nth时迭代器都会发生变异(前进),并且在循环迭代之间永远不会“倒回”。

最后:

fn main() {
    let ascii: Vec<&char> = ASCII_LOWERCASE
        .into_iter()
        .chain(ASCII_UPPERCASE.into_iter().chain(
            ASCII_NUMERIC.into_iter().chain(
                ASCII_SYMBOLS.into_iter(),
            ),
        ))
        .collect();

    for x in 0..95 {
        println!("{}", ascii[x]);
    }
}

将创建一个集合,然后将其编入索引。

请注意,您在集合前面不需要mut,因为它没有变异。

然而,正确的方法是停止使用指数。迭代器已遍历一系列元素,因此您可以直接使用它:

fn main() {
    let ascii = ASCII_LOWERCASE.iter().chain(
        ASCII_UPPERCASE.iter().chain(
            ASCII_NUMERIC.iter().chain(ASCII_SYMBOLS.iter())
        )
    );

    for x in ascii {
        println!("{}", x);
    }
}

答案 1 :(得分:1)

我明白了。 for循环每次都在工作示例中创建一个新集合,因此始终从头开始引用nth。迭代器通过next方法使用,因此失败的版本会在每次nth调用时更改其参考点。