2017-01-15 13 views
5

Chương trình của tôi sử dụng rusqlite để xây dựng cơ sở dữ liệu từ một nguồn dữ liệu khác. Cơ sở dữ liệu được xây dựng nhiều bảng theo cách tương tự, vì vậy tôi nghĩ rằng tôi muốn làm một chức năng tái sử dụng để làm như vậy:Mượn vấn đề với câu lệnh SQL đã biên dịch

fn download_generic<Inserter>(table_name: &str, 
           connection: &mut rusqlite::Connection, 
           inserter: &mut Inserter) 
           -> Result<(), String> 
    where Inserter: FnMut(&str, &json::JsonValue) ->() 
{} 

inserter là một chức năng gắn kết các giá trị đúng từ một tuyên bố trước đó chuẩn bị và thực hiện chèn .

Tôi gọi nó là như thế này:

let mut insert_stmt = connection 
    .prepare("insert or replace into categories values(?,?);") 
    .unwrap(); 

download_generic("categories", 
       &mut connection, 
       &mut |uuid, jsonproperties| { 
        insert_stmt.execute(&[&uuid, &jsonproperties["name"].as_str().unwrap_or("")]); 
       }); 

Tuy nhiên tôi không thể vượt qua &mut connection để download_generic vì nó đã được mượn bởi insert_stmt. Đặt nó vào một RefCell không có ý nghĩa bởi vì tôi không cần thời gian chạy trên cao để thực hiện công việc này.

Tôi có thể thử làm cho insert_stmt được tạo bởi lambda mà bạn chuyển đến download_generic, nhưng sau đó tôi bị choáng ngợp vì phải thêm dấu thời gian ở mọi nơi và dường như không tự nhiên.

+0

Đặt nó vào một 'RefCell' sẽ không hoạt động:' RefCell' chỉ cần kiểm tra tại thời gian chạy thay vì biên dịch thời gian nhưng kiểm tra cơ bản giống nhau được thực hiện => ** Aliasing XOR Mutability **. Câu hỏi hiển nhiên là: bạn không thể chỉ mượn (bất biến) cùng một kết nối? Nếu một khoản vay được yêu cầu duy nhất có thể thay đổi, thì bạn sẽ không may mắn. –

+0

Tôi không thể di chuyển insert_stmt vào lambda bằng cách nào đó để 'download_generic' giữ nó? – njaard

+0

Bạn có thể sử dụng 'prepar_cached' thay vì' chuẩn bị' để có được một tuyên bố chuẩn bị trong phạm vi đóng cửa thay thế không? Bạn sẽ phải vượt qua 'kết nối' để đóng cửa một cách rõ ràng để tránh mâu thuẫn với các khoản vay. –

Trả lời

2

Theo thiết kế, Rust ngăn bạn không có khoản vay không thay đổi và khoản vay có thể thay đổi được trên cùng một đối tượng đang hoạt động cùng một lúc. Điều này là để ngăn chặn con trỏ lủng lẳng và các cuộc đua dữ liệu.

Trong API của rusqlite, một số phương pháp trên Connection yêu cầu có thể thay đổi self và một số phương thức chỉ yêu cầu self không thay đổi. Tuy nhiên, một số phương pháp chỉ yêu cầu đối tượng trả về self không thay đổi mà giữ cho hoạt động vay đó hoạt động; prepare là một ví dụ về điều này. Do đó, miễn là một trong những đối tượng này nằm trong phạm vi, Rust sẽ không cho phép bạn vay một khoản vay có thể thay đổi được trên Connection.

Có thể là lý do tại sao một số phương pháp lấy self bằng tham chiếu có thể thay đổi. Việc yêu cầu tham chiếu có thể thay đổi sẽ đảm bảo khả năng truy cập độc quyền đối tượng đó. Nếu bạn nghĩ rằng có thể không phải là trường hợp cho các phương pháp bạn cần sử dụng, hoặc bạn nghĩ rằng có thể có một cách khác để giải quyết điều này, bạn nên báo cáo một vấn đề cho người bảo trì của thư viện.

Về số prepare cụ thể, bạn có thể làm việc xung quanh các khoản vay xung đột bằng cách gọi số prepare_cached từ trong phạm vi đóng. Để thực hiện điều đó, bạn sẽ phải thực hiện download_generic chuyển số connection trở lại làm tham số cho việc đóng, nếu không bạn sẽ có hai khoản vay có thể thay đổi được trên connection và điều đó không được phép.

+0

'Connection :: prepare' chấp nhận một' & self' không thể thay đổi được, và do đó tôi có thể chuyển 'Statement' được chuẩn bị cùng với' Connection'. Do đó, vấn đề này có thể giải quyết được một cách không đáng kể. – njaard

Các vấn đề liên quan