2015-01-17 19 views
5

Điều gì là sai với điều này:Đảo ngược một chuỗi trong Rust

fn main() { 
    let word: &str = "lowks"; 
    assert_eq!(word.chars().rev(), "skwol"); 
} 

tôi nhận được một lỗi như thế này:

error[E0369]: binary operation `==` cannot be applied to type `std::iter::Rev<std::str::Chars<'_>>` 
--> src/main.rs:4:5 
    | 
4 |  assert_eq!(word.chars().rev(), "skwol"); 
    |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    | 
    = note: an implementation of `std::cmp::PartialEq` might be missing for `std::iter::Rev<std::str::Chars<'_>>` 
    = note: this error originates in a macro outside of the current crate 

cách chính xác để làm điều này là gì?

Trả lời

12

Vấn đề đầu tiên và cơ bản nhất là đây không phải là cách bạn đảo ngược chuỗi Unicode. Bạn đang đảo ngược thứ tự của các điểm mã, nơi bạn muốn đảo ngược thứ tự của đồ thị. Có thể có các vấn đề khác với điều này mà tôi không biết. Văn bản rất khó.

Vấn đề thứ hai được chỉ ra bởi trình biên dịch: bạn đang cố gắng so sánh chuỗi ký tự với trình lặp vòng char. charsrev không tạo ra chuỗi mới, chúng tạo ra các chuỗi lười biếng, như với các trình vòng lặp nói chung. The following works:

/*! 
Add the following to your `Cargo.toml`: 

```cargo 
[dependencies] 
unicode-segmentation = "0.1.2" 
``` 
*/ 
extern crate unicode_segmentation; 
use unicode_segmentation::UnicodeSegmentation; 

fn main() { 
    let word: &str = "loẅks"; 
    let drow: String = word 
     // Split the string into an Iterator of &strs, where each element is an 
     // extended grapheme cluster. 
     .graphemes(true) 
     // Reverse the order of the grapheme iterator. 
     .rev() 
     // flat_map takes each element of an iterator, turns that element into 
     // a new iterator, then outputs the elements of these sub-iterators as 
     // one long chain. In this case, we're turning each grapheme cluster 
     // into an Iterator of code points, then yielding all those code points. 
     // That is, this is now an Iterator of chars from the reversed grapheme 
     // clusters. 
     .flat_map(|g| g.chars()) 
     // Collect all the chars into a new owned String. 
     .collect(); 

    assert_eq!(drow, "skẅol"); 

    // Print it out to be sure. 
    println!("drow = `{}`", drow); 
} 

Lưu ý rằng graphemes từng là trong thư viện chuẩn như một phương pháp không ổn định, do đó trên sẽ phá vỡ với các phiên bản đầy đủ cũ của Rust. Trong trường hợp đó, bạn cần sử dụng UnicodeSegmentation::graphemes(s, true) để thay thế.

+6

Tôi nghĩ bạn có thể chỉ '.rev() thu thập() ', vì' Chuỗi' triển khai 'TừIterator <&str>'. Ngoài ra, fwiw, tôi nghĩ rằng * thực tế * vấn đề cơ bản nhất là hiểu lầm vòng lặp, chuỗi và các loại nói chung (dễ hiểu, nhiều ngôn ngữ không quá "pedantic"), không phải là một số điểm tốt hơn về tính chính xác unicode. – huon

+0

@dbaupp: Tôi cho rằng một vấn đề độc lập với ngôn ngữ thực hiện là * nhiều hơn * cơ bản so với ngôn ngữ cụ thể cho một ngôn ngữ cụ thể. : D Nhưng thật tuyệt khi biết 'Chuỗi' hỗ trợ' TừIterator <&str> '. Một điều đáng tiếc là nó không phân bổ trước dung lượng lưu trữ, nhưng bạn không thể luôn có được thứ bạn muốn ... –

+0

Eh, câu hỏi đặt ra là tại sao một đoạn mã nào đó không biên dịch bằng một ngôn ngữ cụ thể, không phải vì sao nó cho đầu ra không mong muốn (tức là một vấn đề độc lập về ngôn ngữ với thuật toán), vì vậy vấn đề cơ bản đối với câu hỏi đó là các lỗi kiểu Rust cụ thể. Đó là chắc chắn tốt để đề cập đến unicode là khó khăn, mặc dù. – huon

10

Vì, như @DK. đề nghị, .graphemes() không có sẵn trên &str ở ổn định, bạn có thể cũng chỉ cần làm những gì @huon gợi ý trong các ý kiến:.

fn main() { 
    let foo = "palimpsest"; 
    println!("{}", foo.chars().rev().collect::<String>()); 
}