ããã¾ã§ã«ã«ã³ãã¡ã¬ã³ã¹ãªã©ã§çºè¡¨ããè³æãããã«ã¾ã¨ãã¾ãã éææ´æ°ã§ãã
æçµæ´æ°: 2024-02-28
âââ çºè¡¨æ¥éé ã§ä¸¦ãã§ãã¾ã
ç¶ããèªãããã¾ã§ã«ã«ã³ãã¡ã¬ã³ã¹ãªã©ã§çºè¡¨ããè³æãããã«ã¾ã¨ãã¾ãã éææ´æ°ã§ãã
æçµæ´æ°: 2024-02-28
âââ çºè¡¨æ¥éé ã§ä¸¦ãã§ãã¾ã
ç¶ããèªããã®è¨äºã¯ Rust Advent Calendar 2024 ã® 8æ¥ç®ã®è¨äºã§ãã
Rust 㯠wasm ã«ã³ã³ãã¤ã«ã§ããããæå³ãããè¨èªã§ãããã¾ããRust ã³ã¼ãã wasm ã«ã³ã³ãã¤ã«ãã¦ãã¾ãã°ããã©ã¦ã¶ãã¯ããã¨ãã wasm ã©ã³ã¿ã¤ã ã§å®è¡ã§ãã¦ã¨ã¦ã便å©ã§ãã
wasm-bindgen ã使ã㨠JavaScript ããå¼ã³åºããããã¤ã³ã¿ã¼ãã§ã¼ã¹ãèªåã§çæã§ãã¾ããããã« TypeScript ã®åå®ç¾©ãã¡ã¤ã« (.d.ts ãã¡ã¤ã«) ãçæããã¾ãã
ãããå¼æ°ãè¿ãå¤ã« JsValue
ã使ã£ã¦ãã¾ã㨠.d.ts å´ã§ã¯ any
åã«ãªã£ã¦ãã¾ãã¾ããããã§ã¯ãã£ããã®åå®ç¾©ãå°ç¡ãã§ãã
ãã®è¨äºã§ã¯ .d.ts å´ã§ä¸æãåä»ãããã Rust ã³ã¼ããæ¸ããã¨ãç®æ¨ã¨ãã¾ããã.d.ts å´ã§ãã®åã欲ãããªã Rust ã³ã¼ãã§ã¯ããæ¸ããã¨ãããã©ã¯ãã£ã¹ãã²ãããåæãã¦ããã¾ãã
ããã§ç´¹ä»ãã¦ããä¾ã¯ä¸è¨ã®ãªãã¸ããªã«ã¾ã¨ãã¦ãã¾ãã
ã³ã³ãã¤ã«ãã wasm ã TypeScript ããå¼ã³åºããã¹ãã³ã¼ããããã®ã§æåã®ç解ã«å½¹ç«ã¤ã¯ãã§ãã
ä¸è¨ã®ã¯ã¬ã¼ãã使ç¨ãã¾ãã
äºåã« Cargo.toml ã«æ¸ãå ãã¦ããã¾ãããã
[dependencies] wasm-bindgen = "0.2.84" tsify-next = "0.5.4" serde = "1.0.215"
â» âµ
ã¯æ¹è¡ã表ã
TypeScript ã®å | Rust ã§ããæ¸ã | åè | |
---|---|---|---|
â¾ï¸ | number |
u8 , u16 , u32 , i8 , i16 , i32 |
string ããæé»ã«åå¤æããã |
â¾ï¸ | number |
f32 , f64 |
string ããæé»ã«åå¤æããã |
â¾ï¸ | bigint |
u64 , u128 , i64 , i128 |
string ããæé»ã«åå¤æããã |
â¾ï¸ | string |
String , &str |
|
â¾ï¸ | boolean |
bool |
number ããæé»ã«åå¤æããã |
â¾ï¸ | Symbol |
- | ç¡ã |
â¾ï¸ | null |
#[derive(Tsify)]âµ struct Null; |
|
â¾ï¸ | undefined |
- | ç¡ã |
â¾ï¸ | T[] |
Vec<T> |
T ã¯å ·ä½åã§ãªããã°ãããªã |
â¾ï¸ | Uint8Array |
Vec<u8> |
|
â¾ï¸ | Int8Array |
Vec<i8> |
|
â¾ï¸ | Uint16Array |
Vec<u16> |
|
â¾ï¸ | Int16Array |
Vec<i16> |
|
â¾ï¸ | Uint32Array |
Vec<u32> |
|
â¾ï¸ | Int32Array |
Vec<i32> |
|
â¾ï¸ | BigUint64Array |
Vec<u64> , Vec<u128> |
|
â¾ï¸ | BigInt64Array |
Vec<i64> , Vec<i128> |
|
â¾ï¸ | Float32Array |
Vec<f32> |
|
â¾ï¸ | Float64Array |
Vec<f64> |
|
â¾ï¸ | Function |
js_sys::Function |
å¼æ°ãè¿ãå¤ã®åãæ示ã§ããªã |
â¾ï¸ | [T1, T2, T3] |
#[derive(Tsify)]âµ struct MyTuple(T1, T2, T3); |
T1 ãªã©ã¯å ·ä½åã§ãªããã°ãããªã |
â¾ï¸ | "Foo" | "Bar" | "Baz" |
#[derive(Tsify)]âµ enum MyUnion { Foo, Bar, Baz } |
|
â¾ï¸ | T1 | T2 | ... |
#[derive(Tsify)]âµ enum MyUnion { T1, T2, ... } |
T1 ãªã©ã¯å ·ä½åã§ãªããã°ãããªã |
â¾ï¸ | interface { ... } |
#[derive(Tsify)]âµ struct MyInterface { ... } |
|
â¾ï¸ | { prop?: T; } |
#[derive(Tsify)]âµ struct MyInterface { #[tsify(optional)] prop: Option<T> } |
T ã¯å ·ä½åã§ãªããã°ãããªã |
â¾ï¸ | { prop: T | null; } |
#[derive(Tsify)]âµ struct MyInterface { prop: Option<T> } |
T ã¯å ·ä½åã§ãªããã°ãããªã |
â¾ï¸ | Record<K, T> |
#[derive(Tsify)]âµ struct MyRecord(HashMap<K, T>); |
K, T ã¯å ·ä½åã§ãªããã°ãããªã |
â¾ï¸ | Map<K, T> |
#[derive(Tsify)]âµ struct MyMap(HashMap<K, T>); |
features = ["js"] ãå¿
è¦ K, T ã¯å ·ä½åã§ãªããã°ãããªã Record<K, T> ããæé»ã«åå¤æããã |
â¾ï¸ | function f(x?: T) |
fn f(x: Option<T>) { ... } |
T ã¯å ·ä½åã§ãªããã°ãããªã |
â¾ï¸ | namespace { ... } |
#[derive(Tsify)]âµ #[tsify(namespace)]âµ enum MyNamespace { ... } |
ãã以éãå ·ä½çã«è§£èª¬ãã¦ããã¾ãã
JavaScript ã«ã¯7種é¡ã®ããªããã£ãåãããã¾ãã
æ°å¤ number
, é·æ´æ° bigint
, æåå string
, è«çå¤ boolean
, ã·ã³ãã« Symbol
, null
, undefined
ã§ãã
number
number
ã欲ããã¨ãã«ã¯ Rust ã® u8
, u16
, u32
, i8
, i16
, i32
, f32
, f64
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_number_into_rust_u32(n: u32) -> u32 { console::log_1(&format!("value: {:?}", n).into()); return n; }
// .d.ts export function from_ts_number_into_rust_u32(n: number): number;
.d.ts ã§ã¯ã©ãã number
åã«ãªã£ã¦ãã¾ãã¾ããããã¡ãã Rust ã«åã渡ããã¨ãã«ä¿æã§ããå¤ã®ç¯å²ãå¤ãã£ã¦ãã¾ãã
ä¾ãã° i8
ã§åä»ãããã¨ä¿æã§ããã®ã¯ -128 ~ 127 ã§ãã
ã§ã¯ i8
ã®æå°å¤ã»æ大å¤ãè¶
ããå¤ã JavaScript ãã渡ãã¨ã©ããªãã§ããããã
ãªãã¨ããªã¼ãã¼ããã¼ã»ã¢ã³ãã¼ããã¼ãã¦ç¯å²å
ã«åãããã¨ããæåã«ãªãã¾ãã
// JavaScript from_ts_number_into_rust_i8(128); // i8 ã®æå¤§å¤ 127 ãè¶ ãã¦ããï¼ // => log: "value: -128"
åæ¤æ»ã§ãã¨ã©ã¼ã«ãªããå®è¡æã®ä¾å¤ã«ããªããªãã®ã§ããã®æåã«ã¯é©ãããç¥ãã¾ããã
ã¾ã .d.ts 㧠number
ã§åä»ãããããã®ã®ããæ°å¤ã¨ãã¦è§£éå¯è½ãªæååãã渡ããã¨ãå¯è½ã§ãã
å
é¨ã§æ°å¤ã¨ãã¦ãã¼ã¹ããã¾ãã
// JavaScript from_ts_number_into_rust_i8("42"); // æååã渡ã // => log: "value: 42"
bigint
number
ã欲ããã¨ãã«ã¯ Rust ã® u64
, u128
, i64
, i128
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_bigint_into_rust_u64(n: u64) -> u64 { console::log_1(&format!("value: {:?}", n).into()); return n; }
// .d.ts export function from_ts_bigint_into_rust_u64(n: bigint): bigint;
ãã¡ãã bigint
ã渡ããã¨ãå¯è½ã§ããä¾ãã° 9_007_199_254_740_991n
ãªã©ã
ä¸æ¹ã§ number
ã渡ããã¨ããã¨ä¾å¤ãæãããã¾ãã
// JavaScript from_ts_bigint_into_rust_u64(9_007_199_254_740_991n); // => log: "value: 9007199254740991" from_ts_bigint_into_rust_u64(42); // number ã¯æ¸¡ããªã // => ä¾å¤ãæãããã
æ°å¤ã«è§£éå¯è½ãªæååã渡ããä»æ§ãå¥å¨ã§ãã
// JavaScript from_ts_bigint_into_rust_u64("9007199254740991"); // => log: "value: 9007199254740991"
string
string
ã欲ããã¨ãã«ã¯ Rust ã® String
ã¾ã㯠&str
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_string_into_rust_string(s: String) -> String { console::log_1(&format!("value: {:?}", s).into()); return s; }
// .d.ts export function from_ts_string_into_rust_string(s: string): string;
string
以å¤ã®å¤ã渡ãã¨ä¾å¤ãæãããã¾ããæé»ã«æ°å¤ãæåååããããããªæåã¯ããã¾ããã
// JavaScript from_ts_string_into_rust_string(42); // => ä¾å¤ãæãããã
boolean
boolean
ã欲ããã¨ãã«ã¯ Rust ã® bool
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_boolean_into_rust_bool(b: bool) -> bool { console::log_1(&format!("value: {:?}", b).into()); return b; }
// .d.ts export function from_ts_boolean_into_rust_bool(b: boolean): boolean;
JavaScript ããå¼ã³åºãã¨ãã«ã¯ boolean
ã®ä»ã« number
ãåãå
¥ãã¦ãããããã§ãã
0
ã渡ãã° Rust å´ã§ false
ã¨è§£éããã¾ãã0
以å¤ã®å¤ã¯ true
ã¨è§£éããã¾ãã
// JavaScript from_ts_boolean_into_rust_bool(true); // => log: "value: true" from_ts_boolean_into_rust_bool(false); // => log: "value: false" from_ts_boolean_into_rust_bool(1); // => log: "value: true" from_ts_boolean_into_rust_bool(0); // => log: "value: false"
Symbol
Symbol
ãåã渡ãããæ¹æ³ã¯ããã¾ããã
null
é¢æ°ã®å¼æ°ã null
ã§åä»ããããå ´é¢ã¯ç¡ãæ°ããã¾ããããã®ããã«æ¸ãæ¹æ³ã¯ããã¾ãã
Rust ã®ã¦ãããæ§é ä½ (unit struct) ããåãçæãã㨠null
ã«ãªãã¾ãã
// Rust #[derive(Tsify, Serialize, Deserialize, Debug)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct Null; #[wasm_bindgen] pub fn from_ts_null_into_rust_unit_struct(_null: Null) -> Null { console::log_1(&format!("value: {:?}", _null).into()); return _null; }
// .d.ts export type Null = null; export function from_ts_null_into_rust_unit_struct(_null: Null): Null;
null
ã®ã¨ã¤ãªã¢ã¹ã¨ã㦠Null
ãå®ç¾©ããã¾ããã
Null
ãå¼æ°ãè¿ãå¤ã«ä½¿ããã¨ã§ null
ã§åä»ãã§ãã¾ãã
null
ãç»å ´ãããã£ã¨å®ç¨çãªä¾ã¯ string | null
ãªã©ã® Nullable ãªåã§ããããããã«ã¤ãã¦ã¯ãã®è¨äºã®å¾ã®æ¹ã§è§£èª¬ãã¾ãã
undefined
å¼æ°ãè¿ãå¤ã undefined
ã§åä»ãããæ¹æ³ã¯ããã¾ããã
å®ç¨çãªä¾ã¨ãã¦çç¥å¯è½ãªå¼æ°ã表ç¾ããã¨ãã« undefined
ãç»å ´ãã¾ããããã«ã¤ãã¦ã¯ãã®è¨äºã®å¾ã®æ¹ã§è§£èª¬ãã¾ãã
å¼æ°ãè¿ãå¤ã«é ååãæå®ãããã¨ã§è¤æ°ã®å¤ãã¾ã¨ãã¦åãåã£ããè¿ãããã§ãã¾ãã
T[]
T[]
ã欲ããã¨ãã«ã¯ Rust ã® Vec<T>
ã使ãã¾ãã
ãã ã T ã¯å
·ä½åã§ãªãã¨ãã¡ã§ãåãã©ã¡ã¼ã¿ã¼ã使ã£ã¦ fn f<T>(x: Vec<T>) { ... }
ã®ããã«ã¯æ¸ãã¾ããã
// Rust #[wasm_bindgen] pub fn from_ts_array_into_rust_vec(strings: Vec<String>) -> Vec<String> { console::log_1(&format!("value: {:?}", strings).into()); return strings; }
// .d.ts export function from_ts_array_into_rust_vec(strings: (string)[]): (string)[];
Uint8Array
Uint8Array
ã欲ããã¨ãã«ã¯ Rust ã® Vec<u8>
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_uint8array_into_rust_vec(numbers: Vec<u8>) -> Vec<u8> { console::log_1(&format!("value: {:?}", numbers).into()); return numbers; }
// .d.ts export function from_ts_uint8array_into_rust_vec(numbers: Uint8Array): Uint8Array;
Int8Array
Int8Array
ã欲ããã¨ãã«ã¯ Rust ã® Vec<i8>
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_int8array_into_rust_vec(numbers: Vec<i8>) -> Vec<i8> { console::log_1(&format!("value: {:?}", numbers).into()); return numbers; }
// .d.ts export function from_ts_int8array_into_rust_vec(numbers: Int8Array): Int8Array;
Uint16Array
Uint16Array
ã欲ããã¨ãã«ã¯ Rust ã® Vec<u16>
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_uint16array_into_rust_vec(numbers: Vec<u16>) -> Vec<u16> { console::log_1(&format!("value: {:?}", numbers).into()); return numbers; }
// .d.ts export function from_ts_uint16array_into_rust_vec(numbers: Uint16Array): Uint16Array;
Int16Array
Int16Array
ã欲ããã¨ãã«ã¯ Rust ã® Vec<i16>
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_int16array_into_rust_vec(numbers: Vec<i16>) -> Vec<i16> { console::log_1(&format!("value: {:?}", numbers).into()); return numbers; }
// .d.ts export function from_ts_int16array_into_rust_vec(numbers: Int16Array): Int16Array;
Uint32Array
Uint32Array
ã欲ããã¨ãã«ã¯ Rust ã® Vec<u32>
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_uint32array_into_rust_vec(numbers: Vec<u32>) -> Vec<u32> { console::log_1(&format!("value: {:?}", numbers).into()); return numbers; }
// .d.ts export function from_ts_uint32array_into_rust_vec(numbers: Uint32Array): Uint32Array;
Int32Array
Int32Array
ã欲ããã¨ãã«ã¯ Rust ã® Vec<i32>
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_int32array_into_rust_vec(numbers: Vec<i32>) -> Vec<i32> { console::log_1(&format!("value: {:?}", numbers).into()); return numbers; }
// .d.ts export function from_ts_int32array_into_rust_vec(numbers: Int32Array): Int32Array;
BigUint64Array
BigUint64Array
ã欲ããã¨ãã«ã¯ Rust ã® Vec<u64>
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_biguint64array_into_rust_vec(numbers: Vec<u64>) -> Vec<u64> { console::log_1(&format!("value: {:?}", numbers).into()); return numbers; }
// .d.ts export function from_ts_biguint64array_into_rust_vec(numbers: BigUint64Array): BigUint64Array;
BigInt64Array
BigInt64Array
ã欲ããã¨ãã«ã¯ Rust ã® Vec<i64>
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_bigint64array_into_rust_vec(numbers: Vec<i64>) -> Vec<i64> { console::log_1(&format!("value: {:?}", numbers).into()); return numbers; }
// .d.ts export function from_ts_bigint64array_into_rust_vec(numbers: BigInt64Array): BigInt64Array;
Float32Array
Float32Array
ã欲ããã¨ãã«ã¯ Rust ã® Vec<f32>
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_float32array_into_rust_vec(numbers: Vec<f32>) -> Vec<f32> { console::log_1(&format!("value: {:?}", numbers).into()); return numbers; }
// .d.ts export function from_ts_float32array_into_rust_vec(numbers: Float32Array): Float32Array;
Float64Array
Float64Array
ã欲ããã¨ãã«ã¯ Rust ã® Vec<f64>
ã使ãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_float64array_into_rust_vec(numbers: Vec<f64>) -> Vec<f64> { console::log_1(&format!("value: {:?}", numbers).into()); return numbers; }
// .d.ts export function from_ts_float64array_into_rust_vec(numbers: Float64Array): Float64Array;
é¢æ°ã»ã¯ãã¼ã¸ã£ã¼ã§åä»ãããä¸æãæ¹æ³ã¯ç¡ãããã§ãã
éå®çã§ã¯ããã¾ãã Rust ã® js_sys::Function
ã§åä»ããã㨠.d.ts 㧠Function
åãçæããã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_closure_into_js_sys_function(f: js_sys::Function) -> js_sys::Function { console::log_1(&format!("value: {:?}", f).into()); return f; }
// .d.ts export function from_ts_closure_into_js_sys_function(f: Function): Function;
ã¨ã¯ããå¼æ°ãè¿ãå¤ã®åãæ示ã§ããªãã®ã§ãã¾ã²ã¨ã¤ã§ããã
ã¿ãã«ã欲ããã¨ãã«ã¯ Rust ã®ã¿ãã«æ§é ä½ (tuple struct) ã使ãã¾ãã
// Rust #[derive(Tsify, Serialize, Deserialize, Debug)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct MyTuple(u8, String, bool); #[wasm_bindgen] pub fn from_ts_tuple_into_rust_struct(tuple: MyTuple) -> MyTuple { console::log_1(&format!("value: {:?}", tuple).into()); return tuple; }
// .d.ts export type MyTuple = [number, string, boolean]; export function from_ts_tuple_into_rust_struct(tuple: MyTuple): MyTuple;
ã¦ããªã³åã欲ããã¨ãã«ã¯ Rust ã® Enum ã使ãã¾ãã
ç¹ã«ãã使ãæååãªãã©ã«åã®ã¦ããªã³ãè¦ã¦ã¿ã¾ãããã
"Foo" | "Bar" | "Baz"
ã®ãããªåã欲ããã¨ãã«ã¯ãã®ããã«ãã¾ãã
// Rust #[derive(Tsify, Serialize, Deserialize, Debug)] #[tsify(into_wasm_abi, from_wasm_abi)] pub enum StringLiteralTypeUnion { Foo, Bar, Baz, }
// .d.ts export type StringLiteralTypeUnion = "Foo" | "Bar" | "Baz";
å°æåã¯ãã¾ã㧠"foo" | "bar" | "baz"
ã®ãããªåã欲ããã¨ãã«ã¯ã#[serde(rename_all = "camelCase")]
å±æ§ãä»ãã¾ãããã
// Rust #[derive(Tsify, Serialize, Deserialize, Debug)] #[tsify(into_wasm_abi, from_wasm_abi)] #[serde(rename_all = "camelCase")] pub enum StringLiteralTypeUnion { Foo, Bar, Baz, }
// .d.ts export type StringLiteralTypeUnion = "foo" | "bar" | "baz";
Rust ã®å¤ä»ãåæå㯠.d.ts ã§ã¯ object ã®ã¦ããªã³ã¨ãã¦è¡¨ç¾ããã¾ãã
// Rust #[derive(Tsify, Serialize, Deserialize, Debug)] #[tsify(into_wasm_abi, from_wasm_abi)] pub enum ObjectUnion { N(u32), S(String), B(bool), Tuple(u32, String, bool), Named { n: u32, s: String, b: bool }, }
// .d.ts type ObjectUnion = | { N: number } | { S: string } | { B: boolean } | { Tuple: [number, string, boolean] } | { Named: { n: number; s: string; b: boolean } };
ç´ æ´ã« interface ã欲ããã¨ãã«ã¯ Rust ã®æ§é ä½ (named struct) ã使ãã¾ãã
// Rust #[derive(Tsify, Serialize, Deserialize, Debug)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct MyInterface { n: u8, s: String, b: bool, }
// .d.ts export interface MyInterface { n: number; s: string; b: boolean; }
interface ã®ä¸ã§çç¥å¯è½ããããã£ã»Nullable ããããã£ã表ç¾ããã«ã¯ Rust ã® Option<T>
ã使ãã¾ãã
Option<T>
㯠T | null
ã«è§£éããã¾ããããã« #[tsify(optional)]
å±æ§ãä»ãã㨠T | null | undefined
ã«è§£éãããçç¥å¯è½ã«ãªãã¾ãã
// Rust #[derive(Tsify, Serialize, Deserialize, Debug)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct ObjectHasOptionalProperty { pub nullable_property: Option<String>, #[tsify(optional)] pub optional_property: Option<String>, }
// .d.ts export interface ObjectHasOptionalProperty { nullable_property: string | null; optional_property?: string; }
Record<K, T>
åinterface ã§ã¯ããããã決ãããããã¼ããæå®ã§ãã¾ãããä»»æã®ãã¼ãã㤠object ãæ±ãããå ´åã«ã¯ Record<K, T>
åã欲ãããªãã¾ãã
Rust ã® HashMap<K, T>
ã使ãã¾ãã
// Rust #[derive(Tsify, Serialize, Deserialize, Debug)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct MyRecord(HashMap<String, u32>);
// .d.ts export type MyRecord = Record<string, number>;
Map<K, T>
åMap<K, T>
ã欲ããã¨ãã«ã¯ Rust ã® HashMap<K, T>
ã使ãã¾ãã
ãã ã tsify-next ã«å¯¾ã㦠features = ["js"]
ãæå¹ã«ãã¦ã³ã³ãã¤ã«ããå¿
è¦ãããã¾ãããã®ãã Map<K, T>
㨠Record<K, T>
ãå
±åããããã¨ã¯ã§ãã¾ããã
# Cargo.toml [dependencies.tsify-next] version = "0.5.4" features = ["js"]
// Rust #[derive(Tsify, Serialize, Deserialize, Debug)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct MyMap(HashMap<String, u32>);
// .d.ts export type MyMap = Map<string, number>;
é¢æ°ã®å¼æ°ã« Option<T>
ã使ã㨠T | undefined
ã«è§£éããã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_nullable_string_into_rust_option_string(x: Option<String>, y: String) -> String { console::log_1(&format!("value: {:?}", x).into()); console::log_1(&format!("value: {:?}", y).into()); x.unwrap_or(y) }
// .d.ts export function from_ts_nullable_string_into_rust_option_string(x: string | undefined, y: string): string;
ããã«ãã®å¼æ°ãæ«å°¾å¼æ°ã§ããã°çç¥å¯è½å¼æ°ã«ãªãã¾ãã
// Rust #[wasm_bindgen] pub fn from_ts_optional_parameter_into_rust_option_string(x: Option<String>) -> Option<String> { console::log_1(&format!("value: {:?}", x).into()); return x; }
// .d.ts export function from_ts_optional_parameter_into_rust_option_string(x?: string): string | undefined;
Rust ã® Enum ãã TypeScript ã® namespace ãçæã§ãã¾ãã
// Rust #[derive(Tsify, Serialize, Deserialize, Debug)] #[tsify(namespace, into_wasm_abi, from_wasm_abi)] pub enum Color { Red, Blue, Green, Rgb(u8, u8, u8), Hsv { hue: f64, saturation: f64, value: f64, }, }
// .d.ts declare namespace Color { export type Red = "Red"; export type Blue = "Blue"; export type Green = "Green"; export type Rgb = { Rgb: [number, number, number] }; export type Hsv = { Hsv: { hue: number; saturation: number; value: number } }; }
ãããã§ãããããRust ã®å㨠.d.ts ãä¸å¯§ã«å¯¾å¿ã¥ãããã¨ã§ Rust 㨠JavaScript ã®ä¸¡æ¹ãããåãåããåç
§ããã¨ããä½é¨ãå¾ããã¾ãã
wasm-bindgen ã tsify-next ãã¾ã ã¾ã çºå±éä¸ã§ããä»å¾ãã¾ä»¥ä¸ã«åã®è¡¨ç¾åãå¾ããããã¨ãæå¾
ãããã§ããã
ç§ããã¯ä»¥ä¸ã§ãã
ãã®è¨äºã¯ ã¯ã¦ãªã¨ã³ã¸ã㢠Advent Calendar 2024 ã® 2 æ¥ç®ã®è¨äºã§ãã
æ¨æ¥ã¯ id:hogashi ããã®ãquerySelectorAllã®çµæãmapãããã¨ãã¯Array.fromããã¨è¯ããã§ããã
ã©ããã趣å³ã§é¢æ°åè¨èªããã£ã¦ããè
ã§ãã
é·ããé¢æ°åè¨èªããã£ã¦ãªãã£ããç¡åå帰ãå¿ãããã¦ããã®ã§ããããããã¦ãä¸åç¹ã³ã³ããã¼ã¿ã§ç¡åå帰ãä½ãæµããæ¸ãä¸ãã¾ãã
以ä¸ãJavaScript ã®ææ³ã§æ¸ãããã³ã¼ãããã¨ã«èª¬æãã¦ããã¾ãã
ã¾ãã¯ã¢ããã¼ã·ã§ã³ã®ç¢ºèªããã
é常ãå帰é¢æ°ã¯ã
function sum(nums) { if (nums.length === 0) { return 0; } else { const num = nums.pop(); return num + sum(nums); } }
ã¨ãã£ãããã«ãé¢æ°å®ç¾©ã®ä¸ã§èªåèªèº«ãå¼ã¶ãã¨ã§å帰å¦çãè¨è¿°ã§ãã¾ãã
ãã®ä¾ã§ã¯ã return num + sum(nums);
ã®é¨åã§èªåèªèº«ãå¼ãã§ãã¾ããã
ã§ã¯ã以ä¸ã®ãããªå¶ç´ãã¤ã¡ã¼ã¸ãã¦ã¿ã¦ãã ããã
ãã®ãããªå¶éã®ä¸ã§å帰ãæ¸ããããªã£ããã©ãããã°ããã§ããããï¼
ãããªè¦æã«å¿ããããã«äººé¡ã¯ ç¡åå帰 ã¨ããæ¹æ³ãç·¨ã¿åºãã¾ããããã®åã®éããé¢æ°åã«ä¾ããªãå帰å¦çã®æ¹æ³ã§ãã
ä»åã¯ç¡åå帰ã®å ·ä½çãªä½ãæ¹ãè¦ã¦ããã¾ãã
ãããªãã§ãã ä¸åç¹ã³ã³ããã¼ã¿ ã¨ãããã¤ãããã¾ãã
é¢æ°ãå¤æããé¢æ° (é«éé¢æ°) ã®å½¢ããã¦ãã¾ããå®ç¾©ã¯ããã§ãã
const fix = f => (g => g(g))(h => f(y => h(h)(y)));
ãªãã ããã¯ã£ã¦æãã§ãããè½ã¡çã㦠fix(f)
ãã©ã®ããã«å±éããããè¦ã¦ã¿ã¾ãããã
fix(f) â (f => (g => g(g))(h => f(y => h(h)(y))))(f) â (g => g(g))(h => f(y => h(h)(y))) â (h => f(y => h(h)(y)))(h => f(y => h(h)(y))) â f(y => (h => f(y => h(h)(y)))(h => f(y => h(h)(y)))(y)) = f(y => fix(f)(y))
fix(f) = f(y => fix(f)(y))
ã¨ããé¢ä¿ãè¦ãã¾ãããã¨ã¯ãããã¾ã ã¡ãã£ã¨ä½ããããã®ãåãããªãæãã®é¢æ°ã§ããã
ããã©ã¯ãã£ã¨å
·ä½çã« f
ã«ç¹å®ã®é¢æ°ã代å
¥ãã¦ã¿ã¾ãããã
f = next => x => next(x)
ã®å ´åf = next => x => next(x)
ã®ã¨ãã® fix(f)(0)
ãèãã¾ãã
const fix = f => (g => g(g))(h => f(y => h(h)(y))); // fix(f) = f(y => fix(f)(y)) const f = next => x => next(x); fix(f)(0) // fix(f) ã®å®ç¾©ãå±é â f(y => fix(f)(y))(0) // f ã®å®ç¾©ãå±é â (next => x => next(x))(y => fix(f)(y))(0) // ç¡åé¢æ°ãè©ä¾¡ãã â (x => (y => fix(f)(y))(x))(0) â (y => fix(f)(y))(0) â fix(f)(0)
ãªã㨠fix(f)(0)
ãè©ä¾¡ããã¨åã³ fix(f)(0)
ãç¾ãã¾ããã
é¢æ°ãå®è¡ãããã¨ããã¨åãé¢æ°ã®å®è¡ã«è¡ãçãã®ã§ããã®ããã°ã©ã ã¯å»¶ã
ã¨åãé¢æ°ãå¼ã³åºãç¶ãããã¨ã«ãªãã¾ãã
ãã® é¢æ°ã®å¼ã³åºãã延ã ã¨ç¹°ãè¿ããã ã¨ãããã¤ã¯ãå®éã«ãã£ã¦ã¿ã㨠å¦çãç¡éã«ã«ã¼ããã¦åæ¢ããªã ã¨ããæ±ãã«ãªãã§ãããã
ãããªé¢æ°ãå½¹ã«ç«ã¤ã®ãï¼
大ä¸å¤«ãããå°ãå¥ã®ä¾ãè¦ã¦ããã¾ãããã
f = next => x => next(x + 1)
ã®å ´åf = next => x => next(x + 1)
ã®ã¨ããèãã¾ãããã
ããã»ã©ã¨ã¨ã¦ãä¼¼ã¦ãã¾ãã x + 1
ã¨è¶³ãç®ããã¦ãã¾ãã
const fix = f => (g => g(g))(h => f(y => h(h)(y))); // fix(f) = f(y => fix(f)(y)) const f = next => x => next(x + 1); fix(f)(0) â f(y => fix(f)(y))(0) â (next => x => next(x + 1))(y => fix(f)(y))(0) â (x => (y => fix(f)(y))(x + 1))(0) â (y => fix(f)(y))(0 + 1) â fix(f)(0 + 1) â fix(f)(1)
fix(f)(0)
ãè©ä¾¡ãã㦠fix(f)(1)
ã«ãªãã¾ããã
å度 fix(f)(1)
ãè©ä¾¡ãã㨠fix(f)(2)
ã«ãªãã¾ããããã«ç¹°ãè¿ãã° fix(f)(3)
ã«ãªãã¾ãã
const fix = f => (g => g(g))(h => f(y => h(h)(y))); // fix(f) = f(y => fix(f)(y)) const f = next => x => next(x + 1); fix(f)(0) â ... â fix(f)(1) â ... â fix(f)(1 + 1) â fix(f)(2) â ... â fix(f)(2 + 1) â fix(f)(3) â ...
åãé¢æ°ãå¼ã³åºãç¶ãã¦ããã¨ããç¹ã§ã¯å
ã»ã©ã®åãã§ããã®ä¾ã§ãé¢æ°ã®å®è¡ã¯åæ¢ããã«ã¨ã©ã¼ã«ãªãã¾ãã
ãã ä»åº¦ã¯å¼æ°ã®é¨åã§è¨ç®ãè¡ããã¦ããã®ã§ãä½ã å帰å¦çããã¦ããæã ãæã¦ã¾ããã
f = next => x => x > 1 ? x : next(x + 1)
ã®å ´åããä¸æ©è¸ã¿è¾¼ãã§æ¡ä»¶åå²ãå ãã¦ã¿ã¾ãããã
f = next => x => x > 1 ? x : next(x + 1)
ã«ã¤ãã¦èãã¾ãã
const fix = f => (g => g(g))(h => f(y => h(h)(y))); // fix(f) = f(y => fix(f)(y)) const f = next => x => x > 1 ? x : next(x + 1); fix(f)(0) â f(y => fix(f)(y))(0) â (next => x => x > 1 ? x : next(x + 1))(y => fix(f)(y))(0) â (x => x > 1 ? x : (y => fix(f)(y))(x + 1))(0) â 0 > 1 ? 0 : (y => fix(f)(y))(0 + 1) â (y => fix(f)(y))(0 + 1) â fix(f)(0 + 1) â fix(f)(1) â ... â fix(f)(2) â ... â (x => x > 1 ? x : (y => fix(f)(y))(x + 1))(2) â 2 > 1 ? 2 : (y => fix(f)(y))(2 + 1) â 2
ã¤ãã«ç¡éã®é¢æ°å¼ã³åºããåé¿ã§ãã¾ããã
ãã©ã¦ã¶ã§å®è¡ãã¦ã¿ã¦ãåãçµæãå¾ããã¾ãã
f
ãã©ããªå¼ã ã£ããããä¸åº¦è¦ã¦ã¿ã¾ãããã
const f = next => x => x > 1 ? x : next(x + 1);
種æãããã㨠next(~)
ã®é¨åãå帰å¼ã³åºãã«ç¸å½ãã¦ãã¾ãã
æ¡ä»¶åå²ã追å ã㦠next(~)
ã å¼ã³åºããªã ãã¨ã§å帰ãæã¡åããã¨ãã§ããã®ã§ãã
ãã®æåãæç¶çã«æ¸ãã¦ã¿ãã¨ãããªæãã«ãªãã¯ãã§ãã
let x = 0; while (true) { if (x > 2) { return x; } else { x += 1; } }
ã©ãã§ãããï¼æ¡ä»¶åå²ãçµã¿è¾¼ãã å¼ f
ã渡ããã¨ã§ ä½ãå®ç¨çãªå¼ãçµã¿ç«ã¦ãããããªæ°ããã¦ãã ã¨æãã¾ãããï¼
ããããä¸åç¹ã³ã³ããã¼ã¿ã使ã£ãå®ç¨çãªä¾ãè¦ã¦ããã¾ãããã
0以ä¸ã®èªç¶æ° n ã®éä¹ fact(n)
ãè¨ç®ãã¦ã¿ã¾ãã
ã¾ãéä¹é¢æ° fact
ãå®ç¾©ããããã®è£å©é¢æ° _fact
ã次ã®ããã«å®ç¾©ãã¾ãã
const _fact = next => n => n === 1 ? 1 : n * next(n - 1);
ããã fix
ã«ä¸ãã¦å±éãã¦ã¿ã¾ãããã
const fix = f => (g => g(g))(h => f(y => h(h)(y))); // fix(f) = f(y => fix(f)(y)) const _fact = next => n => n === 1 ? 1 : n * next(n - 1); fix(_fact) â (f(y => fix(f)(y)))(_fact) â _fact(y => fix(_fact)(y)) â (next => n => n === 1 ? 1 : n * next(n - 1))(y => fix(_fact)(y)) â n => n === 1 ? 1 : n * (y => fix(_fact)(y))(n - 1)
ã¯ãï¼ ä¸é
æ¼ç®åã® else ç¯ã«æ³¨ç®ãã¦ãã ãã fix(_fact)(y)
ã¨ããå½¢ã§å帰çæ§é ãè¦ãã¦ãã¾ããã
n ã«ãå
·ä½çãªå¤ãå
¥ãã¦ã¿ã¾ãããã fix(_fact)(3)
ãå±éãã¾ãã
fix(_fact)(3) // fix ã®å®ç¾©ã«å¾ã fix(_fact) ãå±é â _fact(y => fix(_fact)(y))(3) // _fact ã®å®ç¾©ã«å¾ãå¼ãå±é â (next => n => n === 1 ? 1 : n * next(n - 1))(y => fix(_fact)(y))(3) â (n => n === 1 ? 1 : n * (y => fix(_fact)(y))(n - 1))(3) â 3 === 1 ? 1 : 3 * (y => fix(_fact)(y))(3 - 1) // ä¸é æ¼ç®åãè©ä¾¡ â 3 * (y => fix(_fact)(y))(3 - 1) // 3 - 1 ãè©ä¾¡ â 3 * (y => fix(_fact)(y))(2) â 3 * fix(_fact)(2) // 以ä¸ãç¹°ãè¿ã â 3 * _fact(y => fix(_fact)(y))(2) â 3 * (next => n => n === 1 ? 1 : n * next(n - 1))(y => fix(_fact)(y))(2) â 3 * (n => n === 1 ? 1 : n * (y => fix(_fact)(y))(n - 1))(2) â 3 * (2 === 1 ? 1 : 2 * (y => fix(_fact)(y))(2 - 1)) â 3 * 2 * (y => fix(_fact)(y))(2 - 1) â 3 * 2 * (y => fix(_fact)(y))(1) â 3 * 2 * fix(_fact)(1) â 3 * 2 * _fact(y => fix(_fact)(y))(1) â 3 * 2 * (next => n => n === 1 ? 1 : n * next(n - 1))(y => fix(_fact)(y))(1) â 3 * 2 * (n => n === 1 ? 1 : n * (y => fix(_fact)(y))(n - 1))(1) â 3 * 2 * (1 === 1 ? 1 : 1 * (y => fix(_fact)(y))(1 - 1)) â 3 * 2 * 1 â 6
ãµã
ããç²ããã¾ã§ãããfix(_fact)(3)
ã 3 * 2 * 1
ã«å±éãããæ§åãè¦ãã¦ãã¾ãã«éä¹è¨ç®ãã¦ããæãã§ããã
ãã¦fix(_fact)(n)
㧠n ã®éä¹ãè¨ç®ã§ãããã¨ãåãã£ãã®ã§ã
const fix = f => (g => g(g))(h => f(y => h(h)(y))); const _fact = next => n => n === 1 ? 1 : n * next(n - 1); const fact = fix(_fact);
ã¨ãã¦éä¹é¢æ° fact()
ãå®ç¾©ãããã¨ãã§ãã¾ããã
ãããã㦠_fact
㨠fact
ã®å®ç¾©ãè¦ã¦ã¿ã¾ãããã
const _fact = next => n => n === 1 ? 1 : n * next(n - 1); const fact = fix(_fact);
_fact
ã®å®ç¾©ã«ã fact
ã®å®ç¾©ã«ãèªåèªèº«ãå¼ã³åºãè¨è¿°ã¯ããã¾ãããããä»åã®ãã¼ãéã èªåèªèº«ãå¼ã³åºããã¨ãªãå帰å¦çãå®ç¾ã§ãã ã¨ãããã¨ã«ãªãã¾ãã
ããã« _fact
ã®å®ç¾©ãããè¦ã¦ããã¨ä»®å¼æ°ã® next
ãã¾ãã§å帰å¼ã³åºãã®ããã«ä½¿ã£ã¦ãããã¨ãåããã¾ãã
å½¢å¼çãªç¥èã¨ãã¦ã¯ããã§ãã
fix
ã«é¢æ° g
ãä¸ãããã¨ã§é¢æ° f
ãå¾ãããf
ã¯é常ã®1å¼æ°é¢æ°ã¨ãã¦æ¯ãèãg
ã®ç¬¬ä¸ä»®å¼æ° next
ã®å¼ã³åºãã¯ãf
ã®å帰å¼ã³åºãã®ããã«æ¯ãèãæ´ãã¦ãã¾ãããï¼å®éã«ç´ã«ææ¸ãã§éç®ãã¦ã¿ãã¨ããç解ãæ·±ã¾ãããç¥ãã¾ããã
å
ã»ã©ã®ä¾ã§è¦ã fact()
ã¯ãã ä¸ã¤ã®å¼æ° n
ãåã1å¼æ°é¢æ°ã§ããã
次ã«2å¼æ°é¢æ°ãç¡åå帰ã§æ¸ãä¾ãè¦ã¦ã¿ã¾ãããã
ä¾ã«åãä¸ããã®ã¯èªç¶æ° m
, n
ã®æ大å
¬ç´æ°ãæ±ããé¢æ° gcd(m, n)
ã§ãã
ã¦ã¼ã¯ãªããã®äºé¤æ³ ã使ã£ã¦è¨ç®ãã¾ãã
ã¾ãã¯ååå帰çã§ãã
const gcd = (m, n) => n === 0 ? m : gcd(n, m % n); gcd(1071, 1029); // => 21
ãããç¡åå帰ã§æ¸ãããã¨ããã§ããå°ã£ããã¨ãããã¾ããããã»ã©ç´¹ä»ããä¸åç¹ã³ã³ããã¼ã¿ fix
ã¯1å¼æ°é¢æ°ãä½ãã¨ãã«ãã使ããªãã®ã§ãã
åé¡ã®è§£æ±ºçã3ã¤ç´¹ä»ãã¾ãã
const fix2 = f => (g => g(g))(h => f((x, y) => h(h)(x, y)));
ãã®ä¸åç¹ã³ã³ããã¼ã¿ fix2
ã¯å
ã»ã©ã¾ã§è¦ã¦ãã fix
ã®2å¼æ°çã§ãã
使ãæ¹ã¯ fix
ã¨å¤ããã¾ããã
const fix2 = f => (g => g(g))(h => f((x, y) => h(h)(x, y))); const _gcd = next => (m, n) => n === 0 ? m : next(n, m % n); const gcd = fix2(_gcd); gcd(1071, 1029); // => 21
ãã¡ãã3å¼æ°é¢æ°ãæ¸ããããªã£ãã3å¼æ°çã® fix3
ãã4å¼æ°é¢æ°ãæ¸ããããªã£ãã4å¼æ°çã® fix4
ãå¿
è¦ã«ãªãã¾ããå°ãé¢åã§ããã
// 3å¼æ°ç const fix3 = f => (g => g(g))(h => f((x, y, z) => h(h)(x, y, z))); // 4å¼æ°ç const fix4 = f => (g => g(g))(h => f((x, y, z, w) => h(h)(x, y, z, w)));
ã«ãªã¼å ã¨ããæ¹æ³ã使ãã¨å¤å¼æ°é¢æ°ã¨åçã®ãã®ã1å¼æ°é¢æ°ã ãã§æ¸ããã¨ãå¯è½ã«ãªãã¾ãã
ä¾ã¨ã㦠Math.pow(x, y)
ã1å¼æ°é¢æ°ã§è¡¨ç¾ããã¨ã
const pow = x => y => Math.pow(x, y); Math.pow(2, 4); // => 16 pow(2)(4); // å¼ã³åºãæ¹ãå¤ããã®ã§æ³¨æ // => 16
pow
ã¯1å¼æ°é¢æ°ã§ãã
ãã ã pow(2)
ã®è¿ãå¤ãã¾ã1å¼æ°é¢æ°ã«ãªã£ã¦ãã¾ããå¼æ°ãä¸ã¤ãã¤æ¸¡ã㦠2åå¼ã³åºã ãã¨ã§2å¼æ°ã§ã®å¼ã³åºãã¨åçã®çµæãå¾ããã¾ãã
ã«ãªã¼åãã¦ãã¾ãã°å
¨ã¦ã®é¢æ°ã¯1å¼æ°é¢æ°ã«ãªãã®ã§ãå
ã»ã©ã® gcd
ã1å¼æ°çã® fix
ã使ã£ã¦å®ç¾©ã§ãã¾ãã
const fix = f => (g => g(g))(h => f(x => h(h)(x))); const _gcd = next => m => n => n === 0 ? m : next(n)(m % n); const gcd = fix(_gcd); gcd(1071)(1029); // ã«ãªã¼åã«ãã£ã¦å¼ã³åºãæ¹ãå¤ããã®ã§æ³¨æ // => 21
ã2å¼æ°ãåãåãé¢æ°ãã¯ã2è¦ç´ ã®ã¿ãã«ã1ã¤åãåãé¢æ°ãã¨åçã§ãã
JavaScript ã«ã¯ã¿ãã«ãç¡ãã®ã§é
åã§ä»£ç¨ããã¨ã
const pow = ([x, y]) => Math.pow(x, y); Math.pow(2, 4); // => 16 pow([2, 4]); // å¼ã³åºãæ¹ãå¤ããã®ã§æ³¨æ // => 16
Math.pow(x, y)
ã¨åçã®è¨ç®ããã1å¼æ°é¢æ° pow([x, y])
ãå®ç¾©ã§ãã¾ããã
1å¼æ°çã® fix
ã使ã£ã¦ãã¿ãã«æ¸¡ãã® gcd
é¢æ°ãå®ç¾©ãã¦ã¿ã¾ãããã
const fix = f => (g => g(g))(h => f(x => h(h)(x))); const _gcd = next => ([m, n]) => n === 0 ? m : next([n, m % n]); const gcd = fix(_gcd); gcd([1071, 1029]); // ã¿ãã«æ¸¡ãã§å¼ã³åºã // => 21
ã©ã®æ¹æ³ã§ã2å¼æ°é¢æ°ã®ç¡åå帰ã«ä¸æã対å¿ã§ãã¦ãã¾ããã
ããã¾ã§è¦ã¦ããä¸åç¹ã³ã³ããã¼ã¿ fix
ãããã使ã£ã¦å®ç¾©ããç¡åå帰é¢æ°ã«é©åã«åä»ãã§ããã®ãæ°ã«ãªãã¾ãããï¼
ãªã㨠TypeScript ãªã fix
ã«é©åã«åãã¤ãããã¨ãå¯è½ã§ãã
ãã®ããã«ãªãã¾ãã
function fix<S, T>(f: (_: (_: S) => T) => (_: S) => T) { type U = (_: U) => (_: S) => T; return (g => g(g))((h: U) => f((y: S) => h(h)(y))); }
åä»ãã® fix
ã使ã£ã¦éä¹é¢æ° fact
ãæ¸ããä¾ã TypeScript Playground ã«ç¨æãã¾ããã
_fact
ã«æä½éã®å注éãã¤ããã ã㧠fact = fix(_fact)
ã®åãæ£ããæ¨è«ããã¦ãã¾ãã
ä¸åç¹ã³ã³ããã¼ã¿ã使ãã¨æ±ºã¾ã£ããã¿ã¼ã³ã§ç¡åå帰ãå®ç¾ã§ãããã¨ãè¦ã¦ãã¾ããã
ã¾ãå¤å¼æ°é¢æ°ã«å¿ç¨ãããã¨ã TypeScript ã«ããåä»ãã«ã¤ãã¦ãç¥ããã¨ãã§ãã¾ããã
ããã§ç´¹ä»ããä¸åç¹ã³ã³ããã¼ã¿ãç¡åå帰ã¯è¨ç®æ©ç§å¦ã®å§ã¾ãã®é ããç 究ããã¦ãããã¼ãã§ããã³ã³ããã¼ã¿çè«ã確ç«ãã¦ãããå 人ã«æè¬ãã¾ãã
ç§ããã¯ä»¥ä¸ã§ãã
ãã®è¨äºã¯ä¸è¨ã®è¨äºã¨ã»ã¼åãå
容ã JavaScript ã§ç¼ãç´ãããã®ã§ãã
ä¸è¨ã®è¨äºã§ã¯ãµã³ãã«ã³ã¼ãã Haskell ã§æ¸ãã¦ãã¾ãããããHaskell ã§ãµã³ãã«ã³ã¼ãæ¸ãã¦èª°ãèªããããï¼ãã¨æã£ãã®ã§ JavaScript ã§æ¸ãç´ãã¾ããã
ä¸åç¹ã³ã³ããã¼ã¿ã®åä»ãã«ã¤ãã¦ã¯ä¸è¨ã®è¨äºã大ãã«åèã«ããã¦ããã ãã¾ããã
é
åãã¨ããè¦ç´ ãå«ããã©ãã調ã¹ãã«ã¯ Array.prototype.includes
ã使ãã¾ãã
const arr = [1, 2, 4, 8, 16]; arr.includes(4); // => true arr.includes(7); // => false
ã¨ããã§ãJavaScript ã«ã¯ Set ã¨ãããã¼ã¿åããããåãããã« Set.prototype.has
ã使ã£ã¦è¦ç´ ãå«ãã§ãããæ¤ç´¢ã§ãã¾ãã
const set = new Set([1, 2, 4, 8, 16]); set.has(4); // => true set.has(7); // => false
mdn ãè¦ãã¨è¦ç´ æ°ãåããªã Array.prototype.includes
ãã Set.prototype.has
ã®ã»ããéã㨠æ¸ãã¦ããã¾ã ã
has ã¡ã½ããã¯ãå¤ã Set å ã«ãããã©ããããã§ãã¯ãã¾ãã
ããã¯ã以åã« Set ã«è¿½å ãããè¦ç´ ã®ã»ã¨ãã©ã確èªãããããå¹³åããã¨é«éãªã¢ããã¼ãã使ç¨ãã¾ãã
ç¹ã«ã Array ãªãã¸ã§ã¯ãã® length ã Set ãªãã¸ã§ã¯ãã® size ã¨çããå ´åãå¹³åã㦠Array.prototype.includes ã¡ã½ããããéããªãã¾ãã
æ¬å½ã§ããããï¼å®éã«ãã³ããã¼ã¯è¨æ¸¬ãã¦ã¿ã¾ããã
Array.prototype.includes
ãã Set.prototype.has
ã®ã»ããéã
è¨æ¸¬ã«ã¯ Deno.bench ã使ãã¾ãã
ã¾ãè¨æ¸¬ãããå¦çãã³ã¼ãã«èµ·ããã¾ãã
import { assert } from "jsr:@std/assert"; import { crypto } from "jsr:@std/crypto/crypto"; // 1,000,000 è¦ç´ ã®é åãä½ã // è¦ç´ ã¯ä½ã§ãããã®ã§ uuid ãè©°ãã¦ãã const arr = Array.from({ length: 1_000_000 }, () => crypto.randomUUID()); // æ¤ç´¢å¯¾è±¡ãç¨æãã const found = arr[Math.floor(Math.random() * arr.length)]; // ããã¯è¦ã¤ãã const notfound = crypto.randomUUID(); // ããã¯è¦ã¤ãããªã // ãããããè¨æ¸¬ Deno.bench({ name: 'Array.prototype.includes', fn() { assert(arr.includes(found)); assert(!arr.includes(notfound)); }, });
ããã¦ã³ãã³ã deno bench example.js
ã§ãã³ããã¼ã¯ãå®è¡ãã¾ãã
$ deno bench example.js CPU | Apple M2 Pro Runtime | Deno 2.1.1 (aarch64-apple-darwin) file:///Users/todays_mitsui/works/temp/example.js benchmark time/iter (avg) iter/s (min ⦠max) p75 p99 p995 -------------------------- ----------------------------- --------------------- -------------------------- Array.prototype.includes 3.9 ms 258.6 ( 3.7 ms ⦠4.3 ms) 3.9 ms 4.3 ms 4.3 ms
ããã¨ãã®ããã«çµæã表示ããã¾ãã
ã§ã¯å ·ä½çã«æ¯è¼ãã¦ã¿ã¾ãããã
Array.prototype.includes
vs in
æ¼ç®å vs Set.prototype.has
Array.prototype.includes
㨠in
æ¼ç®å 㨠Set.prototype.has
ã®å®è¡ã«ãããæéãæ¯ã¹ã¾ãã
è¨æ¸¬ã«ä½¿ã£ãã³ã¼ã㯠ãã ã«ããã¾ãã
è¦ç´ æ°1,000,000件㮠Array 㨠Object 㨠Set ãä½ã£ã¦æ¯è¼ãã¦ãã¾ãã
$ deno bench array_vs_object_vs_set.js CPU | Apple M2 Pro Runtime | Deno 2.1.1 (aarch64-apple-darwin) file:///Users/todays_mitsui/works/temp/array_vs_object_vs_set.js benchmark time/iter (avg) iter/s (min ⦠max) p75 p99 p995 -------------------------- ----------------------------- --------------------- -------------------------- Array.prototype.includes 3.1 ms 317.5 ( 2.9 ms ⦠3.7 ms) 3.4 ms 3.6 ms 3.7 ms in operator 15.9 ns 62,780,000 ( 15.7 ns ⦠34.0 ns) 15.8 ns 18.5 ns 19.2 ns Set.prototype.has 13.1 ns 76,210,000 ( 13.0 ns ⦠15.8 ns) 13.1 ns 14.1 ns 14.6 ns
åä½ãæãã¦ã¿ãã¨ã
time/iter (avg) | iter/s | |
---|---|---|
Array.prototype.includes | 3.1 ms | 317.5 |
in operator | 0.0000159 ms | 62,780,000.0 |
Set.prototype.has | 0.0000131 ms | 76,210,000.0 |
ã¨ããããã§å§åçã« Set.prototype.has
ãéãããã§ãã
Object ãã in
æ¼ç®åã§æ¢ãã®ãããªãéãã§ããã
å ã»ã©ã®è¨æ¸¬ã§ã¯ Array, Object, Set ãä½ãæéã¯è¨æ¸¬ãããæ¤ç´¢ã«ãããæéã®ã¿ã対象ã«ãã¦ãã¾ããã
ã§ã¯ä»»æã® Array ãä¸ããããã¨ããæ¤ç´¢ã®ããã« Object ã Set ãåæåããã¨ãããããããªãã¨ãããªããããªã·ãã¥ã¨ã¼ã·ã§ã³ã§ã¯ã©ãã§ããããã
ãã®ã·ãã¥ã¨ã¼ã·ã§ã³ãæ³å®ãããªã Object ã Set ã®åæåãè¨æ¸¬ã«å«ããã¹ãã§ããã
ãã®å ´åã®ã³ã¼ãã ãã ã§ãã
å®è¡ãã¦ã¿ã¾ãã
$ deno bench array_vs_object_vs_set_2.js CPU | Apple M2 Pro Runtime | Deno 2.1.1 (aarch64-apple-darwin) file:///Users/todays_mitsui/works/temp/array_vs_object_vs_set_2.js benchmark time/iter (avg) iter/s (min ⦠max) p75 p99 p995 -------------------------- ----------------------------- --------------------- -------------------------- Array.prototype.includes 4.0 ms 247.4 ( 4.0 ms ⦠4.2 ms) 4.0 ms 4.2 ms 4.2 ms in operator 109.0 ms 9.2 ( 96.1 ms ⦠153.1 ms) 110.4 ms 153.1 ms 153.1 ms Set.prototype.has 84.8 ms 11.8 ( 72.4 ms ⦠146.7 ms) 76.8 ms 146.7 ms 146.7 ms
ã¯ããåæåã®æéãå å³ãã㨠in
æ¼ç®åã Set.prototype.has
ãé
ãã¨ããçµæã«ãªãã¾ããã
å ã»ã©ã®çµæã¨åããã¦ã¾ã¨ããã¨ã
æ¤ç´¢ | åæå + æ¤ç´¢ | |
---|---|---|
Array.prototype.includes | 3.1 ms | - |
in operator | 0.0000159 ms | 109.0 ms |
Set.prototype.has | 0.0000131 ms | 84.8 ms |
ãã®ããã«ã
æ°åã ãæ¤ç´¢ããã ãã§ããã°ãObject ã Set ãä½ããæç´ã« Array.prototype.includes
ã使ã£ãã»ãããã¼ã¿ã«ã§éããªãããã§ãã
æ°åå以ä¸ã®æ¤ç´¢ãç¹°ãè¿ãã®ã§ããã°åæåã®ã³ã¹ããæã£ã¦ã§ã Object ã Set ãä½ã£ãã»ããæå©ã«ãªãã¾ãã
ãã£ãããªã®ã§ Array ãã Object ã Set ãä½ãã®ã«ãããæéã測ã£ã¦ã¿ã¾ãã
è¦ç´ æ°ã10件~1,000,000件ã®å ´åã§è¦ã¦ã¿ã¾ãããã
è¨æ¸¬ã«ä½¿ã£ãã³ã¼ã㯠ãã ã§ãã
$ deno bench array_to.js CPU | Apple M2 Pro Runtime | Deno 2.1.1 (aarch64-apple-darwin) file:///Users/todays_mitsui/works/temp/array_to.js benchmark time/iter (avg) iter/s (min ⦠max) p75 p99 p995 ------------------------------------- ----------------------------- --------------------- -------------------------- Array -> Set > length: 10 159.9 ns 6,256,000 (150.3 ns ⦠195.0 ns) 163.7 ns 190.9 ns 194.4 ns Array -> Set > length: 100 2.2 µs 453,800 ( 2.1 µs ⦠3.1 µs) 2.2 µs 3.1 µs 3.1 µs Array -> Set > length: 1,000 26.0 µs 38,510 ( 24.5 µs ⦠160.3 µs) 25.6 µs 33.4 µs 38.0 µs Array -> Set > length: 10,000 369.5 µs 2,706 (339.4 µs ⦠916.9 µs) 363.2 µs 722.2 µs 789.4 µs Array -> Set > length: 100,000 3.8 ms 262.1 ( 3.6 ms ⦠4.5 ms) 4.1 ms 4.4 ms 4.5 ms Array -> Set > length: 1,000,000 94.0 ms 10.6 ( 78.9 ms ⦠118.7 ms) 97.2 ms 118.7 ms 118.7 ms Array -> Object > length: 10 178.1 ns 5,615,000 (163.7 ns ⦠586.9 ns) 176.4 ns 321.6 ns 341.2 ns Array -> Object > length: 100 1.9 µs 521,300 ( 1.9 µs ⦠2.1 µs) 1.9 µs 2.1 µs 2.1 µs Array -> Object > length: 1,000 21.6 µs 46,290 ( 18.4 µs ⦠150.1 µs) 22.7 µs 30.5 µs 91.3 µs Array -> Object > length: 10,000 335.2 µs 2,983 (287.7 µs ⦠976.0 µs) 320.2 µs 730.0 µs 797.1 µs Array -> Object > length: 100,000 6.4 ms 155.5 ( 5.7 ms ⦠7.3 ms) 6.7 ms 7.3 ms 7.3 ms Array -> Object > length: 1,000,000 107.9 ms 9.3 ( 96.2 ms ⦠171.6 ms) 102.2 ms 171.6 ms 171.6 ms
è¦ç´ æ° | Array -> Object | Array -> Set |
---|---|---|
10 | 0.0001781 ms | 0.0001599 ms |
100 | 0.0019 ms | 0.0022 ms |
1,000 | 0.0216 ms | 0.0260 ms |
10,000 | 0.3352 ms | 0.3695 ms |
100,000 | 6.4 ms | 3.8 ms |
1,000,000 | 107.9 ms | 94.0 ms |
Object 㨠Set ã§å¤§ããªå·®ãããããã§ã¯ãªããè¦ç´ ãå¢ãããã¨ã«ããå½±é¿ã大ããããã«è¦ãã¾ãã
éã« Object ã Set ãæã£ã¦ããç¶æ
ãã Array ãã»ããã¨ãã«ã¯ã©ããããã®ã³ã¹ãããããã®ã§ããããã
è¦ç´ æ°1,000,000件㮠Object 㨠Set ã«å¯¾ãã¦ãObject.key(obj)
, Array.from(set.keys())
ãæ¯ã¹ã¦ã¿ã¾ãã
è¨æ¸¬ã«ä½¿ã£ãã³ã¼ã㯠ãã ã§ãã
$ deno bench array_from.js CPU | Apple M2 Pro Runtime | Deno 2.1.1 (aarch64-apple-darwin) file:///Users/todays_mitsui/works/temp/array_from.js benchmark time/iter (avg) iter/s (min ⦠max) p75 p99 p995 -------------------- ----------------------------- --------------------- -------------------------- Object.keys 131.1 ms 7.6 (122.1 ms ⦠160.5 ms) 135.8 ms 160.5 ms 160.5 ms Set.prototype.keys 1.5 ms 657.1 ( 1.4 ms ⦠2.2 ms) 1.5 ms 2.1 ms 2.2 ms
è¦ç´ æ° | Object -> Array | Set -> Array |
---|---|---|
1,000,000 | 131.1 ms | 1.5 ms |
æå¤ã«ã Set ãã Array ãä½ãæ¹ã Object ããä½ãã®ã«æ¯ã¹ã¦80åã»ã©éãã¨ããçµæã«ãªãã¾ããã
Set ããè¦ç´ ãæ¤ç´¢ããã®ã¯ç¢ºãã«éãããã ã Set ãä½ãã®ã«ããªãã®æéããããã
å°ãæ®å¿µãªçµæã§ããã
ç§ããã¯ä»¥ä¸ã§ãã