2016-12-13 2 views
2

Я обернув библиотеку C, и она имеет стандартный вид контекста объекта:Ограничение объектов время жизни в Rust

library_context* context = library_create_context(); 

И затем, используя которые вы можете создать несколько объектов:

library_object* object = library_create_object(context); 

И уничтожить их обоих:

library_destroy_object(object); 
library_destroy_context(context); 

Так я обернут это в Rust структур:

struct Context { 
    raw_context: *mut library_context, 
} 

impl Context { 
    fn new() -> Context { 
     Context { 
      raw_context: unsafe { library_create_context() }, 
     } 
    } 

    fn create_object(&mut self) -> Object { 
     Object { 
      raw_object: unsafe { library_create_object(self.raw_context) }, 
     } 
    } 
} 

impl Drop for Context { 
    fn drop(&mut self) { 
     unsafe { 
      library_context_destroy(self.raw_context); 
     } 
    } 
} 

struct Object { 
    raw_object: *mut library_object, 
} 

impl Drop for Object { 
    fn drop(&mut self) { 
     unsafe { 
      library_object_destroy(self.raw_object); 
     } 
    } 
} 

Так что теперь я могу это сделать, и это похоже на работу:

fn main() { 
    let mut ctx = Context::new(); 
    let ob = ctx.create_object(); 
} 

Однако, я также могу это сделать:

fn main() { 
    let mut ctx = Context::new(); 
    let ob = ctx.create_object(); 
    drop(ctx); 

    do_something_with(ob); 
} 

Т.е. контекст библиотеки уничтожается до того, как создаются объекты.

Могу ли я каким-либо образом использовать систему жизни Rust для предотвращения компиляции вышеуказанного кода?

+1

Пожалуйста, произведите [MCVE] при задании вопросов. Представленный код не работает с 7 ошибками неопределенных элементов. Также возможно, что вы можете сделать это больше ** M **, делая это ** C **. – Shepmaster

ответ

4

Да, просто использовать нормальные времена жизни:

#[derive(Debug)] 
struct Context(u8); 

impl Context { 
    fn new() -> Context { 
     Context(0) 
    } 

    fn create_object(&mut self) -> Object { 
     Object { 
      context: self, 
      raw_object: 1, 
     } 
    } 
} 

#[derive(Debug)] 
struct Object<'a> { 
    context: &'a Context, 
    raw_object: u8, 
} 

fn main() { 
    let mut ctx = Context::new(); 
    let ob = ctx.create_object(); 
    drop(ctx); 

    println!("{:?}", ob); 
} 

Это потерпит неудачу с

error[E0505]: cannot move out of `ctx` because it is borrowed 
    --> src/main.rs:26:10 
    | 
25 |  let ob = ctx.create_object(); 
    |    --- borrow of `ctx` occurs here 
26 |  drop(ctx); 
    |   ^^^ move out of `ctx` occurs here 

Иногда люди любят использовать PhantomData, но я не уверен, что я вижу преимущество здесь:

fn create_object(&mut self) -> Object { 
    Object { 
     marker: PhantomData, 
     raw_object: 1, 
    } 
} 

#[derive(Debug)] 
struct Object<'a> { 
    marker: PhantomData<&'a()>, 
    raw_object: u8, 
} 
+0

Aha Я пробовал это, но получил это немного неправильно! Благодаря! – Timmmm

+0

@Timmmm обратите внимание, что выбор '& mut self' для' create_object' означает, что вы не можете создать второй объект, хотя он выглядит так, как будто 'Context' по-прежнему сильно заимствован и/или вы не можете его изменить потому что по-прежнему остается неизменный заем; не уверен, что это будет соответствовать вашим ожиданиям. – Shepmaster

+0

А это объясняет вторую проблему, которую я испытывал. Есть ли способ удалить 'mut'-ness, все еще имея функцию take' & mut self'? Что-то вроде 'context: self as & Context,'? – Timmmm

Смежные вопросы