遍历 JavaScript 值

返回 js_sys::Iterator 的方法

一些 JavaScript 集合具有用于遍历其值或键的方法

这些方法返回 js_sys::Iterator,它是 JavaScript 对象的 Rust 表示,该对象具有一个 next 方法,该方法要么返回迭代中的下一个项目,要么表示迭代已完成,要么抛出错误。也就是说,js_sys::Iterator 代表一个实现了 鸭子类型 JavaScript 迭代协议 的对象。

js_sys::Iterator 可以通过引用(转换为 js_sys::Iter<'a>)或通过值(转换为 js_sys::IntoIter)转换为 Rust 迭代器。Rust 迭代器将产生类型为 Result<JsValue> 的项目。如果它产生 Ok(...),则 JS 迭代器协议返回了一个元素。如果它产生 Err(...),则 JS 迭代器协议抛出了一个异常。

#![allow(unused)]
fn main() {
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn count_strings_in_set(set: &js_sys::Set) -> u32 {
    let mut count = 0;

    // Call `keys` to get an iterator over the set's elements. Because this is
    // in a `for ... in ...` loop, Rust will automatically call its
    // `IntoIterator` trait implementation to convert it into a Rust iterator.
    for x in set.keys() {
        // We know the built-in iterator for set elements won't throw
        // exceptions, so just unwrap the element. If this was an untrusted
        // iterator, we might want to explicitly handle the case where it throws
        // an exception instead of returning a `{ value, done }` object.
        let x = x.unwrap();

        // If `x` is a string, increment our count of strings in the set!
        if x.is_string() {
            count += 1;
        }
    }

    count
}
}

遍历任何实现迭代器协议的 JavaScript 对象

您可以手动测试一个对象是否实现了 JS 的鸭子类型迭代器协议,如果实现了,则将其转换为 js_sys::Iterator,然后您可以最终遍历它。但是,您不需要手动执行此操作,因为我们已将其捆绑为 js_sys::try_iter 函数!

例如,我们可以编写一个函数,该函数从任何 JS 可迭代对象中收集数字,并将它们作为 Array 返回

#![allow(unused)]
fn main() {
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn collect_numbers(some_iterable: &JsValue) -> Result<js_sys::Array, JsValue> {
    let nums = js_sys::Array::new();

    let iterator = js_sys::try_iter(some_iterable)?.ok_or_else(|| {
        "need to pass iterable JS values!"
    })?;

    for x in iterator {
        // If the iterator's `next` method throws an error, propagate it
        // up to the caller.
        let x = x?;

        // If `x` is a number, add it to our array of numbers!
        if x.as_f64().is_some() {
            nums.push(&x);
        }
    }

    Ok(nums)
}
}