rust - 遍历选项的内容或特定值

标签 rust

假设我们有以下 C 代码(假设 srclen == dSTLen 并且长度可以被 64 整除)。

void stream(uint8_t *dst, uint8_t *src, size_t dstlen) {
    int i;
    uint8_t block[64];
    while (dstlen > 64) {
        some_function_that_initializes_block(block);
        for (i=0; i<64; i++) {
            dst[i] = ((src != NULL)?src[i]:0) ^ block[i];
        }
        dst += 64;
        dstlen -= 64;
        if (src != NULL) { src += 64; }
    }
}

这是一个函数,它接受一个源和一个目标,并将源与某个值进行异或 函数计算。当 source 设置为 NULL 指针时,dst 只是计算值。

在 rust 中,当 src 不能为 null 时,这样做非常简单,我们可以这样做:

fn stream(dst: &mut [u8], src: &[u8]) {
    let mut block = [0u8, ..64];
    for (dstchunk, srcchunk) in dst.chunks_mut(64).zip(src.chunks(64)) {
        some_function_that_initializes_block(block);
        for (d, (&s, &b)) in dstchunk.iter_mut().zip(srcchunk.iter().zip(block.iter())) {
            *d = s ^ b;
        }
    }
}

但是让我们假设我们希望能够模仿原始的 C 函数。然后我们想做这样的事情:

fn stream(dst: &mut[u8], osrc: Option<&[u8]>) {
    let srciter = match osrc {
        None => repeat(0),
        Some(src) => src.iter()
    };
    // the rest of the code as above
}

唉,这行不通,因为 repeat(0) 和 src.iter() 有不同的类型。然而,使用 trait 对象似乎无法解决这个问题,因为我们收到一个编译器错误,提示 cannot convert to a trait object because trait 'core::iter::Iterator' is not object safe.(标准库中也没有将迭代器分块的函数)。

有什么好的方法可以解决这个问题,还是我应该在匹配语句的每个分支中复制代码?

最佳答案

您可以调用一个通用的内部函数,而不是在每个臂中重复代码:

fn stream(dst: &mut[u8], osrc: Option<&[u8]>) {
    fn inner<T>(dst: &mut[u8], srciter: T) where T: Iterator<u8> {
        let mut block = [0u8, ..64];
        //...
    }

    match osrc {
        None => inner(dst, repeat(0)),
        Some(src) => inner(dst, src.iter().map(|a| *a))
    }
}

注意附加的 map使两个迭代器兼容(Iterator<u8>)。


如您所述,Iterator没有内置的分块方法。让我们合并 Vladimir 的解决方案并对 block 使用迭代器:

fn stream(dst: &mut[u8], osrc: Option<&[u8]>) {
    const CHUNK_SIZE: uint = 64;

    fn inner<'a, T>(dst: &mut[u8], srciter: T) where T: Iterator<&'a [u8]> {
        let mut block = [0u8, ..CHUNK_SIZE];
        for (dstchunk, srcchunk) in dst.chunks_mut(CHUNK_SIZE).zip(srciter) {
            some_function_that_initializes_block(block);
            for (d, (&s, &b)) in dstchunk.iter_mut().zip(srcchunk.iter().zip(block.iter())) {
                *d = s ^ b;
            }
        }
    }

    static ZEROES: &'static [u8] = &[0u8, ..CHUNK_SIZE];

    match osrc {
        None => inner(dst, repeat(ZEROES)),
        Some(src) => inner(dst, src.chunks(CHUNK_SIZE))
    }
}

关于rust - 遍历选项的内容或特定值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26974226/

相关文章:

openssl - 同时使用 git2 和 hyper : openssl linked more than once

rust - 错误[E0507] : Cannot move out of borrowed content

rust - Rust函数返回包含参数引用的对象可正常编译,但当&self包含在参数列表中时无法编译

rust - 如何对向量的子集进行操作?

iterator - 具有内部可变性的 Vec

rust - 您可以存储可用于访问 AnyMap 的任意类型吗?

rust - 使用 syn 时如何从 Option<T> 获取 T?

rust - Rust 是否跟踪唯一的对象 ID,我们可以打印它们吗?

sockets - Rust 中的套接字服务器不接收

rust - 使用作为闭包参数传​​递的引用调用可变方法时无法推断出适当的生命周期