Вы должны быть крайне осторожны с дублированием ваших данных - одна копия находится на стороне JS, а затем на стороне WASM в Rust. Проблема здесь в том, что Group.add
перемещает значение так, что после того, как вы вызвали group.add, внутренний внутренний указатель кучи (поддерживаемый кодом взаимодействия, сгенерированным wasm-bindgen) изменится, и предыдущая копия станет недействительной, поэтомузначения, вставленные в list
, в значительной степени бесполезны.
Rust-y способ справиться с этой ситуацией состоит в том, чтобы вместо этого сохранить список заимствованных значений и явно управлять временем жизни, чтобы этот списокне переживает своих элементов. К сожалению, wasm-bindgen не допускает явных объявлений времени жизни экспортируемых структур, поэтому эта опция отсутствует.
В идеале вся логика, связанная с работой с векторами, должна существовать только в Rust и быть скрытой от JavaScript. Если вам действительно нужно иметь доступ к векторам в обоих местах, самое простое грубое решение - добавить геттер в группу и использовать его в качестве "мастер-копии". Код будет выглядеть так:
#[wasm_bindgen]
#[derive(Copy, Clone)]
pub struct Vector3 {
x: f32,
y: f32,
z: f32,
}
#[wasm_bindgen]
impl Vector3 {
#[wasm_bindgen(constructor)]
pub fn new() -> Vector3 {
Vector3 { x:0.0, y:0.0, z:0.0 }
}
pub fn get_x(&self) -> f32 {
self.x
}
pub fn get_y(&self) -> f32 {
self.y
}
pub fn get_z(&self) -> f32 {
self.z
}
}
#[wasm_bindgen]
pub struct Group{
list: Vec<Vector3>,
}
#[wasm_bindgen]
impl Group {
#[wasm_bindgen(constructor)]
pub fn new() -> Group {
Group { list: vec![] }
}
pub fn add(&mut self, vec: Vector3) {
self.list.push(vec);
}
pub fn get_at(&self, idx: usize) -> Vector3 {
self.list[idx]
}
}
Тогда сторона JavaScript будет выглядеть так:
...
setTimeout(() => {
for (let i = 0; i < list.length; i++) {
const vect = group.get_at(i);
console.log(vect.get_x());
}
}, 1000);
...
, и мы избавимся от list
в целом.
ПРИМЕЧАНИЕ: это ДЕЙСТВИТЕЛЬНО плохой способ управления списками , потому что каждый раз, когда вы вызываете get_at
, вы создаете еще одну копию вектора, поэтому, если ваш код слишком тяжел для вычислений, то происходит утечка памятиможет быть проблемой. К сожалению, wasm-bindgen не допускает заимствованные возвращаемые значения, поэтому клонирование является практически единственным вариантом, если вам нужен весь кортеж за один вызов.
Если вы не против иметь дело со многими небольшими вызовами на стороне JS, то одной из наиболее очевидных оптимизаций будет разделение get_at
и преобразование его в get_x_at
, get_y_at
, get_z_at
таким образом избегая необходимости переносить экземпляр Vector через границу wasm.
Еще лучше, возможно, вы могли бы придумать другой способ разбиения проблемных областей, чтобы векторам вообще не приходилось пересекать границу сборки.
Надеюсь, это поможет!