Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement slice_shift_char using the std library

Tags:

rust

I'd like to use the &str method slice_shift_char, but it is marked as unstable in the documentation:

Unstable: awaiting conventions about shifting and slices and may not be warranted with the existence of the chars and/or char_indices iterators

What would be a good way to implement this method, with Rust's current std library? So far I have:

fn slice_shift_char(s: &str) -> Option<(char, &str)> {
    let mut ixs = s.char_indices();
    let next = ixs.next();
    match next {
        Some((next_pos, ch)) => {
            let rest = unsafe {
                s.slice_unchecked(next_pos, s.len())
            };
            Some((ch, rest))
        },
        None => None
    }
}

I'd like to avoid the call to slice_unchecked. I'm using Rust 1.1.

like image 891
Marius Danila Avatar asked Jul 07 '15 21:07

Marius Danila


2 Answers

Well, you can look at the source code, and you'll get https://github.com/rust-lang/rust/blob/master/src/libcollections/str.rs#L776-L778 and https://github.com/rust-lang/rust/blob/master/src/libcore/str/mod.rs#L1531-L1539 . The second:

fn slice_shift_char(&self) -> Option<(char, &str)> {
    if self.is_empty() {
        None
    } else {
        let ch = self.char_at(0);
        let next_s = unsafe { self.slice_unchecked(ch.len_utf8(), self.len()) };
        Some((ch, next_s))
    }
}

If you don't want the unsafe, you can just use a normal slice:

fn slice_shift_char(&self) -> Option<(char, &str)> {
    if self.is_empty() {
        None
    } else {
        let ch = self.char_at(0);
        let len = self.len();
        let next_s = &self[ch.len_utf8().. len];
        Some((ch, next_s))
    }
}
like image 100
Steve Klabnik Avatar answered Nov 19 '22 11:11

Steve Klabnik


The unstable slice_shift_char function has been deprecated since Rust 1.9.0 and removed completely in Rust 1.11.0.

As of Rust 1.4.0, the recommended approach of implementing this is:

  1. Use .chars() to get an iterator of the char content
  2. Iterate on this iterator once to get the first character.
  3. Call .as_str() on that iterator to recover the remaining uniterated string.
fn slice_shift_char(a: &str) -> Option<(char, &str)> {
    let mut chars = a.chars();
    chars.next().map(|c| (c, chars.as_str()))
}

fn main() {
    assert_eq!(slice_shift_char("hello"), Some(('h', "ello")));
    assert_eq!(slice_shift_char("ĺḿńóṕ"), Some(('ĺ', "ḿńóṕ")));
    assert_eq!(slice_shift_char(""), None);
}
like image 5
kennytm Avatar answered Nov 19 '22 11:11

kennytm