Rust 如何在切片时达到与take_相当的效果?

Rust 如何在切片时达到与take_相当的效果?,rust,slice,Rust,Slice,Rust切片目前不支持某些迭代器方法,即take_while。为切片实现take_while的最佳方法是什么 const STRHELLO:&'static[u8] = b"HHHello"; fn main() { let subslice:&[u8] = STRHELLO.iter().take_while(|c|(**c=='H' as u8)).collect(); println!("Expecting: {}, Got {}",STRHELLO.sl

Rust切片目前不支持某些迭代器方法,即take_while。为切片实现take_while的最佳方法是什么

const STRHELLO:&'static[u8] = b"HHHello";

fn main() {
    let subslice:&[u8] = STRHELLO.iter().take_while(|c|(**c=='H' as u8)).collect();
    println!("Expecting: {}, Got {}",STRHELLO.slice_to(3),subslice);
    assert!(subslice==STRHELLO.slice_to(3));
}
导致错误的原因:

<anon>:6:74: 6:83 error: the trait `core::iter::FromIterator<&u8>` is not implemented for the type `&[u8]`

首先,您遇到的问题是
collect
是关于创建一个新集合,而slice是关于引用现有数组中的一个连续的项目范围(无论是否动态分配)

我担心,由于traits的性质,原始容器(
STRHELLO
)是一个连续范围的事实已经丢失,并且无法在事实发生后重建。我还担心,任何使用“通用”迭代器的方法都无法得到所需的输出;类型系统必须以某种方式承载以下事实:

  • 原始容器是一个连续的范围
  • 迄今为止执行的操作链保留了此属性
这可能是可行的或不可行的,但我现在看不到它完成了,我不确定它可以以什么方式优雅地实现


另一方面,你可以自己动手:

fn take_while<'a>(initial: &'a [u8], predicate: |&u8| -> bool) -> &'a [u8] { // '
    let mut i = 0u;
    for c in initial.iter() {
        if predicate(c) { i += 1; } else { break; }
    }
    initial.slice_to(i)
}

注:
'H'作为u8
可以重写为
b'H'
,如图所示,与字符串对称。

通过一些重练习,可以使用股票迭代器实现此功能:

use std::raw::Slice;
use std::mem::transmute;

/// Splice together to slices of the same type that are contiguous in memory.
/// Panics if the slices aren't contiguous with "a" coming first.
/// i.e. slice b must follow slice a immediately in memory.
fn splice<'a>(a:&'a[u8], b:&'a[u8]) -> &'a[u8] {
    unsafe {
        let aa:Slice<u8> = transmute(a);
        let bb:Slice<u8> = transmute(b);
        let pa = aa.data as *const u8;
        let pb = bb.data as *const u8;
        let off = aa.len as int; // Risks overflow into negative!!!
        assert!(pa.offset(off) == pb, "Slices were not contiguous!");
        let cc = Slice{data:aa.data,len:aa.len+bb.len};
        transmute(cc)
    }
}

/// Wrapper around splice that lets you use None as a base case for fold
/// Will panic if the slices cannot be spliced!  See splice.
fn splice_for_fold<'a>(oa:Option<&'a[u8]>, b:&'a[u8]) -> Option<&'a[u8]> {
   match oa {
       Some(a) => Some(splice(a,b)),
       None => Some(b),
   }
}

/// Implementaton using pure iterators
fn take_while<'a>(initial: &'a [u8], 
                   predicate: |&u8| -> bool) -> Option<&'a [u8]> {
    initial
        .chunks(1)
        .take_while(|x|(predicate(&x[0])))
        .fold(None, splice_for_fold)
}

如果您只需要花点时间,Matthieu的实现会更干净。无论如何,我还是要发布这篇文章,因为这可能是一条解决在切片上干净地使用迭代器函数这一更普遍问题的途径

老兄,回答得真好!当我坐在这里怀疑答案可能是这样的时候,你实际上实现了它。也许片上的iter()可以一次返回包含单个项的子片,然后你可以使用类似collect的东西来重新合并冗余的子片?@andrewvagner:老实说,我只是不知道这里的API是什么。仍然只是随口说说而已,但如果我的一般想法可行,也许你所需要的就是每个子片()?生成迭代器,或者使用splice()将内容重新拼接在一起?也许splice会为非连续结果返回一个切片迭代器…@AndrewVagner:在没有编译时检查的情况下,返回一个切片迭代器“尽可能连接起来”的想法似乎很巧妙。
use std::raw::Slice;
use std::mem::transmute;

/// Splice together to slices of the same type that are contiguous in memory.
/// Panics if the slices aren't contiguous with "a" coming first.
/// i.e. slice b must follow slice a immediately in memory.
fn splice<'a>(a:&'a[u8], b:&'a[u8]) -> &'a[u8] {
    unsafe {
        let aa:Slice<u8> = transmute(a);
        let bb:Slice<u8> = transmute(b);
        let pa = aa.data as *const u8;
        let pb = bb.data as *const u8;
        let off = aa.len as int; // Risks overflow into negative!!!
        assert!(pa.offset(off) == pb, "Slices were not contiguous!");
        let cc = Slice{data:aa.data,len:aa.len+bb.len};
        transmute(cc)
    }
}

/// Wrapper around splice that lets you use None as a base case for fold
/// Will panic if the slices cannot be spliced!  See splice.
fn splice_for_fold<'a>(oa:Option<&'a[u8]>, b:&'a[u8]) -> Option<&'a[u8]> {
   match oa {
       Some(a) => Some(splice(a,b)),
       None => Some(b),
   }
}

/// Implementaton using pure iterators
fn take_while<'a>(initial: &'a [u8], 
                   predicate: |&u8| -> bool) -> Option<&'a [u8]> {
    initial
        .chunks(1)
        .take_while(|x|(predicate(&x[0])))
        .fold(None, splice_for_fold)
}
const STRHELLO:&'static[u8] = b"HHHello";
let subslice: &[u8] = super::take_while(STRHELLO, |c|(*c==b'H')).unwrap();
println!("Expecting: {}, Got {}",STRHELLO.slice_to(3), subslice);
assert!(subslice == STRHELLO.slice_to(3));