2017-01-15 6 views
5

내 프로그램은 rusqlite를 사용하여 다른 데이터 소스에서 데이터베이스를 빌드합니다. 데이터베이스는 같은 방식으로 여러 테이블을 구축, 그래서 내가 재사용 가능한 기능은 그렇게 할 수 있도록 거라고 생각 :컴파일 된 SQL 문에서 문제 생기기

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

inserter가 이전에 준비된 문장에서 올바른 값을 결합하여 삽입을 수행하는 기능입니다 .

나는 다음과 같이 호출 : 그것은 이미 insert_stmt에 의해 차용되고 있기 때문에

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("")]); 
       }); 

그러나 나는 download_generic&mut connection를 전달할 수 없습니다. RefCell에 넣으면이 작업을 수행하기 위해 런타임 오버 헤드가 필요하지 않으므로 이해가되지 않습니다.

람다가 download_generic으로 전달한 insert_stmt을 만들려고 시도해 볼 수는 있지만, 평생 마커를 사방에 추가해야하므로 부담 스럽습니다. 어쨌든 부 자연스럽게 보입니다.

+0

'RefCell'에 넣으면 작동하지 않습니다 :'RefCell'은 컴파일 타임 대신 런타임에 간단히 검사하지만 동일한 근본 검사는 => ** Aliasing XOR Mutability **로 수행됩니다. 분명한 질문은 : 똑같은 연결을 빌릴 수는 없습니까? 필요한 하나의 빌림이 변경 가능하면 운이 없어진 것입니다. –

+0

'download_generic'이 그것을 유지할 수 있도록 어떻게 든 lambda에 insert_stmt를 옮길 수는 없습니까? – njaard

+0

'prepare' 대신'prepare_cached'를 사용하여 클로저 내에서 준비된 문장을 얻을 수 있습니까? 상충되는 borrow를 피하기 위해서 클로저에'connection'을 명시 적으로 전달해야합니다. –

답변

2

의도적으로 Rust는 동일한 개체에서 동시에 변경할 수없는 차용 및 변경 가능한 차용을 방지합니다. 포인터와 데이터 경합이 끊어지는 것을 방지합니다.

rusqlite의 API에서 Connection의 일부 메소드에는 변경 가능한 self이 필요하며 일부 메소드에는 변경 불가능한 self 만 필요합니다. 그러나 불변의 것만 필요로하는 메소드들 중 일부는 액티브하게 유지하는 객체를 반환한다. prepare이 그 예입니다. 따라서 이러한 오브젝트 중 하나가 범위 내에 있으면 Rust는 Connection에서 변경 가능한 차용을 허용하지 않습니다.

일부 메소드가 변경 가능한 참조로 self을 사용하는 이유가있을 수 있습니다. 변경 가능한 참조를 요구하면 호출 수신자가 해당 객체에 독점적으로 액세스 할 수 있습니다. 사용 방법에 해당하지 않을 수도 있다고 생각하거나이를 해결할 다른 방법이 있다고 생각되면 도서관 관리자에게 문제를보고해야합니다.

특히 prepare과 관련하여 충돌이있는 차용을 해결하려면 대신 닫음 내에서 prepare_cached을 호출하면됩니다. 이를 수행하려면 download_genericconnection을 매개 변수로 다시 전달해야합니다. 그렇지 않으면 connection에 두 개의 변경 가능한 차용을 허용하며 허용되지 않습니다.

+0

'Connection :: prepare'는 변경 불가능한'& self'을 받아들입니다. 따라서 준비된'Statement'를'Connection' 자체와 함께 전달할 수 있습니다. 따라서이 문제는 간단히 해결할 수 있습니다. – njaard