Чтобы узнать о 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!
Итак, вопросы: что я сделал неправильно, почему это происходит и как это исправить?
Правда ли, что все утверждения, кроме последних двух компиляций? – delnan
Трудно это понять, потому что вы предоставили только часть реализации (что понятно, учитывая сложность). Не уверен, что это поможет, но: 'get_class()' возвращает что-то из жизни '' a'? В качестве альтернативы, возможно, вы могли бы рассмотреть аннотацию следующим образом: 'T1: 'aa + JObject <'a>, T2:' bb + JObject <'b>' и указать 'where 'a:' aa, 'b:' bb'? (':' означает «переживания») – mdup
Здесь я думал, что JVM использует одноэлементный шаблон, и вы можете получить его из любого места с помощью 'getjvm' или чего-то еще. Беглый googling, кажется, поддерживает это: http://database.developer-works.com/article/15552998/Multiple+JVM+instances – ArtemGr