如何索引Rust中的String

Sam*_*ers 27 string indexing rust

我试图在Rust中索引一个字符串,但编译器抛出一个错误.我的代码(Project Euler problem 4,playground):

fn is_palindrome(num: u64) -> bool {
    let num_string = num.to_string();
    let num_length = num_string.len();

    for i in 0 .. num_length / 2 {
        if num_string[i] != num_string[(num_length - 1) - i] {
            return false;
        }
    }

    true
}
Run Code Online (Sandbox Code Playgroud)

错误:

error[E0277]: the trait bound `std::string::String: std::ops::Index<usize>` is not satisfied
 --> <anon>:7:12
  |
7 |         if num_string[i] != num_string[(num_length - 1) - i] {
  |            ^^^^^^^^^^^^^
  |
  = note: the type `std::string::String` cannot be indexed by `usize`
Run Code Online (Sandbox Code Playgroud)

有没有理由String不能索引?那我该如何访问数据呢?

Chr*_*gan 28

在Rust中执行此类操作的正确方法不是索引而是迭代.这里的主要问题是Rust的字符串以UTF-8编码,UTF-8是Unicode字符的可变长度编码.如果长度可变,则不查看字符串就无法确定第n个字符的存储位置.这也意味着访问第n个字符的运行时间为O(n)!

在这种特殊情况下,您可以迭代字节,因为已知您的字符串只包含字符0-9(迭代字符是更通用的解决方案,但效率稍差).

这是一些实现这个(游乐场)的惯用代码:

fn is_palindrome(num: u64) -> bool {
    let num_string = num.to_string();
    let half = num_string.len() / 2;

    num_string.bytes().take(half).eq(num_string.bytes().rev().take(half))
}
Run Code Online (Sandbox Code Playgroud)

我们同时遍历字符串中的字节前进(num_string.bytes().take(half))和后退(num_string.bytes().rev().take(half)); 这.take(half)部分是为了减少完成的工作量.然后我们简单地将一个迭代器与另一个迭代器进行比较,以确保在每一步中第n个和第n个最后一个字节是等价的; 如果是,则返回true; 如果没有,那就错了.

  • FWIW,`String`具有直接的[`as_bytes`](http://doc.rust-lang.org/master/collections/string/struct.String.html#method.as_bytes)。此外,您可以使用[`std :: iter :: order :: equals`](http://doc.rust-lang.org/master/std/iter/order/fn.equals.html)。而不是`all`:equals(iter.take(n),iter.rev()。take(n))。 (2认同)
  • 顺便说一句,约定意味着导入`std :: iter :: order`并调用`order :: equals(...,...)`(我只是在评论中没有这样做,因为它会很吵) 。 (2认同)

Vla*_*eev 23

是的,最近删除了索引到字符串.这样做是因为Rust字符串在内部是UTF-8,所以索引本身的概念是不明显的,人们倾向于滥用它:字节索引很快,但几乎总是不正确 - 当你的文本包含非ASCII符号时,字节索引可能让你进入一个角色,如果你需要文本处理,这是非常糟糕的,而char索引不是免费的,因为UTF-8是可变长度编码.

如果您确定您的字符串仅包含ASCII字符,则可以使用返回字节切片的as_bytes()type(using &str方法)或char()方法i:

let num_string = num.to_string();

// ...

let b: u8 = num_string.as_bytes()[i];
let c: char = b as char;  // if you need to get the character as a unicode code point
Run Code Online (Sandbox Code Playgroud)

如果需要字符索引,则应使用as_bytes()方法:

num_string.chars().nth(i).unwrap()
Run Code Online (Sandbox Code Playgroud)

  • FWIW,`String`永远不会被编入索引.索引删除仅适用于`&str`. (7认同)
  • 我想现在,``char_at()``也被删除了...(rustc 1.23.0-nightly(79cfce3d3 2017-11-12)) (7认同)

Ang*_*gel 20

如果您要查找的内容类似于索引,则可以使用

.chars().nth()在一个字符串上.


.chars()- >返回char字符串切片的s上的迭代器.

.nth() - >返回迭代器的第n个元素 Option


现在您可以通过多种方式使用上述方法,例如:

let s: String = String::from("abc");
//If you are sure
println!("{}", s.chars().nth(x).unwrap());
//or if not
println!("{}", s.chars().nth(x).expect("message"));
Run Code Online (Sandbox Code Playgroud)

  • 值得注意的是,“Chars::nth(n)”消耗 n 个字符,而不仅仅是简单的索引。正如文档所述_在同一个迭代器上多次调用 nth(0) 将返回不同的元素。_ (5认同)
  • 如果您确实不确定第 N 个字符是否存在,则使用“expect()”与“unwrap()”将**不能**防止恐慌。无论如何,代码都会出现恐慌,但期望会提供自定义恐慌消息。另请参阅:/sf/ask/4291110701/ (2认同)

小智 8

您可以将 aString&stra转换vec为 a 字符,然后索引该vec.

例如:

fn main() {
    let s = "Hello world!";
    let my_vec: Vec<char> = s.chars().collect();
    println!("my_vec[0]: {}", my_vec[0]);
    println!("my_vec[1]: {}", my_vec[1]);
}

Run Code Online (Sandbox Code Playgroud)

这里有一个活生生的例子

  • 表现如何?我认为字符串字节已被复制。 (4认同)