Tôi mới vào Rust và đọc Các Rust Programming Language, và trong Lỗi Xử lý phần there is a "case study" mô tả một chương trình để đọc dữ liệu từ một tập tin CSV bằng cách sử dụng csv
và rustc-serialize
thư viện (sử dụng getopts
để phân tích cú pháp đối số).Return iterator lười biếng mà phụ thuộc vào dữ liệu được phân bổ trong chức năng
Tác giả viết hàm search
mà bước qua các hàng của tệp csv bằng cách sử dụng đối tượng csv::Reader
và thu thập các mục có trường 'thành phố' khớp với giá trị được chỉ định vào vectơ và trả về. Tôi đã thực hiện một cách tiếp cận hơi khác so với tác giả, nhưng điều này không ảnh hưởng đến câu hỏi của tôi. chức năng (làm việc) của tôi trông như thế này:
extern crate csv;
extern crate rustc_serialize;
use std::path::Path;
use std::fs::File;
fn search<P>(data_path: P, city: &str) -> Vec<DataRow>
where P: AsRef<Path>
{
let file = File::open(data_path).expect("Opening file failed!");
let mut reader = csv::Reader::from_reader(file).has_headers(true);
reader.decode()
.map(|row| row.expect("Failed decoding row"))
.filter(|row: &DataRow| row.city == city)
.collect()
}
nơi loại DataRow
chỉ là một kỷ lục,
#[derive(Debug, RustcDecodable)]
struct DataRow {
country: String,
city: String,
accent_city: String,
region: String,
population: Option<u64>,
latitude: Option<f64>,
longitude: Option<f64>
}
Bây giờ, tác giả đặt ra, là "tập thể dục cho người đọc" sợ hãi, vấn đề sửa đổi hàm này để trả về một trình lặp thay vì một vectơ (loại bỏ cuộc gọi đến collect
). Câu hỏi của tôi là: Làm thế nào điều này có thể được thực hiện ở tất cả, và những cách súc tích và thành ngữ nhất để làm điều đó là gì?
Một nỗ lực đơn giản mà tôi nghĩ được chữ ký đúng loại là
fn search_iter<'a,P>(data_path: P, city: &'a str)
-> Box<Iterator<Item=DataRow> + 'a>
where P: AsRef<Path>
{
let file = File::open(data_path).expect("Opening file failed!");
let mut reader = csv::Reader::from_reader(file).has_headers(true);
Box::new(reader.decode()
.map(|row| row.expect("Failed decoding row"))
.filter(|row: &DataRow| row.city == city))
}
Tôi trả về một đối tượng đặc điểm của loại Box<Iterator<Item=DataRow> + 'a>
để không phải tiếp xúc với các nội Filter
loại, và nơi mà các đời 'a
được giới thiệu chỉ để tránh phải tạo bản sao cục bộ city
. Nhưng điều này không biên dịch được vì reader
không sống đủ lâu; nó được cấp phát trên ngăn xếp và do đó được deallocated khi hàm trả về.
Tôi đoán điều này có nghĩa là reader
phải được cấp phát trên heap (tức là đóng hộp) ngay từ đầu hoặc bằng cách nào đó đã di chuyển khỏi ngăn xếp trước khi chức năng kết thúc. Nếu tôi đã trả lại một sự đóng cửa, đây chính xác là vấn đề sẽ được giải quyết bằng cách làm cho nó đóng cửa move
. Nhưng tôi không biết làm thế nào để làm một cái gì đó tương tự khi tôi không trả lại một chức năng. Tôi đã thử xác định một loại trình vòng lặp tùy chỉnh có chứa dữ liệu cần thiết, nhưng tôi không thể làm cho nó hoạt động được, và nó càng ngày càng xấu đi (không tạo quá nhiều mã này, tôi chỉ đưa nó vào hiển thị các hướng chung của những nỗ lực của tôi):
fn search_iter<'a,P>(data_path: P, city: &'a str)
-> Box<Iterator<Item=DataRow> + 'a>
where P: AsRef<Path>
{
struct ResultIter<'a> {
reader: csv::Reader<File>,
wrapped_iterator: Option<Box<Iterator<Item=DataRow> + 'a>>
}
impl<'a> Iterator for ResultIter<'a> {
type Item = DataRow;
fn next(&mut self) -> Option<DataRow>
{ self.wrapped_iterator.unwrap().next() }
}
let file = File::open(data_path).expect("Opening file failed!");
// Incrementally initialise
let mut result_iter = ResultIter {
reader: csv::Reader::from_reader(file).has_headers(true),
wrapped_iterator: None // Uninitialised
};
result_iter.wrapped_iterator =
Some(Box::new(result_iter.reader
.decode()
.map(|row| row.expect("Failed decoding row"))
.filter(|&row: &DataRow| row.city == city)));
Box::new(result_iter)
}
This question dường như liên quan đến cùng một vấn đề, nhưng tác giả của câu trả lời giải quyết nó bằng cách làm cho các dữ liệu liên quan static
, mà tôi không nghĩ là một sự thay thế cho điều này câu hỏi.
Tôi đang sử dụng Rust 1.10.0, phiên bản ổn định hiện tại từ gói Arch Linux rust
.
Tôi muốn cảm ơn bạn vì đã đặt câu hỏi độc đáo. Nhiều khách truy cập thường xuyên không thể hiện nhiều sự chuẩn bị, người hỏi ít lần đầu tiên. Thanh danh! – Shepmaster
@Shepmaster Cảm ơn, tôi đã cố hết sức để viết một câu hỏi hay, và có vẻ như tôi đã có một câu trả lời đúng chất lượng cho nó! Tuy nhiên, cảm ơn cho chỉnh sửa phong cách của bạn. –