2015-05-27 2 views
4

Чтобы узнать о Rust, я пишу library обертывающий JNI. Я столкнулся с множеством жизненных проблем и храбро сражался с компилятором, чтобы решить их, но с этим я просто сдаюсь. Вот проблема.Переменные имеют разные времена жизни, когда они должны иметь одинаковые

Теперь JNI является интерфейсом к виртуальной машине Java, поэтому каждый Java-объект должен быть привязан к виртуальной машине. Для этого я создал «тип указателя VM» JavaVM, который в основном представляет собой оболочку для указателя и интерфейс для создания объектов JavaEnv, которые являются только обертками для JNIEnv *, а также поставщики более безопасного интерфейса для большинство методов JNI.

Для того, чтобы объявить, что объект JavaEnv привязан к виртуальной машине я сделал следующее:

pub struct JavaEnv<'a> { 
    phantom: PhantomData<&'a JavaVM>, 
    ... 
} 

Теперь, если я правильно понимаю, все объекты JavaEnv будут привязан к какому-либо объекту JavaVM по жизни, и не переживут этого, чего я хочу.

JavaEnv - это интерфейс для манипулирования Java-объектами (и некоторыми другими вещами). Теперь все типы JNI объектов реализации признака:

pub trait JObject<'a>: Drop { 
    fn get_env(&self) -> &'a JavaEnv<'a>; 
    ... 
} 

и сами все выглядеть следующим образом:

pub struct JavaObject<'a> { 
    env: &'a JavaEnv<'a>, 
    ... 
} 

pub struct JavaClass<'a> { 
    env: &'a JavaEnv<'a>, 
    ... 
} 

Теперь, если снова я правильно понимаю, все JavaObject-s будет привязан к какой-то JavaEnv объект по времени жизни, который, в свою очередь, привязан к объекту JavaVM.

Наконец, Java является языком с эталонными по умолчанию семантики, поэтому объект сравнения просто неглубокий справочник сравнения, и я хотел, чтобы отразить его в интерфейсе Rust:

impl<'a, R: 'a + JObject<'a>> PartialEq<R> for JavaObject<'a> { 
    fn eq(&self, other: &R) -> bool { 
     self.get_env().is_same_object(self, other) 
    } 
} 

impl<'a, R: 'a + JObject<'a>> PartialEq<R> for JavaClass<'a> { 
    fn eq(&self, other: &R) -> bool { 
     self.get_env().is_same_object(self, other) 
    } 
} 

pub fn JavaEnv::is_same_object<T1: 'a + JObject<'a>, T2: 'a + JObject<'a>>(&self, obj1: &T1, obj2: &T2) -> bool { 
    unsafe { 
     ((**self.ptr).IsSameObject)(self.ptr, obj1.get_obj(), obj2.get_obj()) == JNI_TRUE 
    } 
} 

Это не работает. Вот тест:

let (cls, cap) = JavaClass::find(&env, "java/lang/String", cap).unwrap(); 
let (obj /*of class java/lang/String*/, cap) = cls.alloc(cap).unwrap(); 
let cls1 /*also java/lang/String*/ = obj.get_class(&cap); 
assert!(cls1 == cls); 
let (sobj /*also of java/lang/String*/, cap) = JavaString::new(&env, "hi!", cap).unwrap(); 
assert!(cls1 != sobj); 
let scls /*also java/lang/String*/ = sobj.get_class(&cap); 
assert!(scls == cls1); 
assert!(scls == cls); 
// TODO: somehow these cls1, scls and cls have different lifetimes (or not?) 
// So those two asserts do not compile!! 
assert!(cls1 == scls); 
assert!(cls == scls); 

Чтобы «исправить» это я должен был изменить код э:

impl<'a, 'b, R: 'b + JObject<'b>> PartialEq<R> for JavaObject<'a> { 
    fn eq(&self, other: &R) -> bool { 
     self.get_env().is_same_object(self, other) 
    } 
} 

impl<'a, 'b, R: 'b + JObject<'b>> PartialEq<R> for JavaClass<'a> { 
    fn eq(&self, other: &R) -> bool { 
     self.get_env().is_same_object(self, other) 
    } 
} 

pub fn JavaEnv::is_same_object<'b, T1: 'a + JObject<'a>, T2: 'b + JObject<'b>>(&self, obj1: &T1, obj2: &T2) -> bool { 
    unsafe { 
     ((**self.ptr).IsSameObject)(self.ptr, obj1.get_obj(), obj2.get_obj()) == JNI_TRUE 
    } 
} 

Но я не хочу, чтобы сравнить JObjects присоединенного к различным ВМ! И еще больше: я просто не понимаю, как эти объекты оказались разными параметрами жизни? Все они были получены из одного JavaEnv и, следовательно, одного и того же JavaVM!

Итак, вопросы: что я сделал неправильно, почему это происходит и как это исправить?

+0

Правда ли, что все утверждения, кроме последних двух компиляций? – delnan

+1

Трудно это понять, потому что вы предоставили только часть реализации (что понятно, учитывая сложность). Не уверен, что это поможет, но: 'get_class()' возвращает что-то из жизни '' a'? В качестве альтернативы, возможно, вы могли бы рассмотреть аннотацию следующим образом: 'T1: 'aa + JObject <'a>, T2:' bb + JObject <'b>' и указать 'where 'a:' aa, 'b:' bb'? (':' означает «переживания») – mdup

+0

Здесь я думал, что JVM использует одноэлементный шаблон, и вы можете получить его из любого места с помощью 'getjvm' или чего-то еще. Беглый googling, кажется, поддерживает это: http://database.developer-works.com/article/15552998/Multiple+JVM+instances – ArtemGr

ответ

2

Я считаю, что ваша основная предпосылка имеет проблему. Проверьте этот пример код:

fn are_equal<'a>(a: &'a u8, b: &'a u8) -> bool { 
    *a == *b 
} 

fn main() { 
    let a = 42; 

    { 
     let b = 84; 
     println!("{}", are_equal(&a, &b)); 
    } 
} 

Здесь у нас есть метод, который принимает два аргумента ссылочных с пожизненным параметром 'a. Тем не менее, вы можете ясно видеть, что фактические времена жизни a и bmain) равны не то же самое - a пережитки b из-за окончания блока.

Все, что требуется, это то, что существует некоторое время жизни, которое может унифицировать оба параметра, а есть - область внутреннего блока.Это не означает, что весь срок службы должен быть в точности равным.

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