ข้ามไปยังเนื้อหา

ชนิดของค่า (Value Types)

WebAssembly เป็น stack machine แบบมีชนิด (typed) ค่าทุกตัวบน stack มีชนิดที่ชัดเจน และฟังก์ชันทุกตัวประกาศอย่างแน่ชัดว่ารับและผลิตชนิดใดบ้าง แต่ต่างจากภาษาส่วนใหญ่ Wasm มีชุดของชนิดให้เลือกที่เล็กมาก

WebAssembly มีชนิดของค่าทั้งหมดสี่ชนิดพอดี:

TypeWidthKind
i3232-bitInteger
i6464-bitInteger
f3232-bitFloat
f6464-bitFloat

ในระดับ Wasm ไม่มีสตริง บูลีน อาเรย์ หรืออ็อบเจกต์ ทุกอย่างเป็นตัวเลข ตรรกะแบบบูลีนถูกแทนด้วยค่า i32 โดยที่ 0 หมายถึง false และค่าใด ๆ ที่ไม่ใช่ศูนย์หมายถึง true

แต่ละชนิดมีคำสั่ง const ที่ push ค่าลิเทอรัล:

(module
(func (export "answer") (result i32)
i32.const 42))

สำหรับ float 64 บิต:

(module
(func (export "pi") (result f64)
f64.const 3.14159265358979))

และสำหรับจำนวนเต็ม 64 บิต — สังเกตว่า i64 มีความพิเศษเมื่อข้ามไปยัง JavaScript:

(module
(func (export "bignum") (result i64)
i64.const 1000000000000))

ชนิด number ของ JavaScript เป็น float 64 บิต ซึ่งสามารถแทนจำนวนเต็มได้อย่างแม่นยำถึง 2^53 เท่านั้น แต่ i64 สามารถเก็บค่าที่เกินกว่านั้นไปไกลมาก เพื่อรักษาความแม่นยำเต็มที่ WebAssembly JavaScript API จะแปลงค่าที่คืนกลับชนิด i64 ให้เป็น BigInt แทนที่จะเป็น number นั่นหมายความว่า typeof result === 'bigint' — ไม่ใช่ 'number'

คุณสามารถตรวจสอบสิ่งนี้ได้ใน runner ด้านล่าง

WebAssembly
ตัวเลือกBenefitCost
เขียน WAT เองเห็นชัดว่าทุกค่าบน stack มีชนิดกำกับตายตัว (i32, i64, f32, f64) ช่วยให้เข้าใจ type system ของ Wasm อย่างละเอียดต้องเลือก const/instruction ให้ตรงชนิดเองทุกครั้ง ผิดชนิดแล้ว validation ไม่ผ่านทันที
ปล่อยให้ compiler generate Wasm (Rust/AssemblyScript)compiler แปลงชนิดจากภาษาต้นทางไปเป็น i32/i64/f32/f64 ให้อัตโนมัติ ลดโอกาสพลาดเรื่อง typeต้องเชื่อใจ compiler ในการแปลงชนิด เช่น i64 เป็น BigInt โดยไม่รู้รายละเอียดว่าเกิดอะไรขึ้นตรงกลาง
  • push ค่าด้วย instruction ผิดชนิด เช่นใช้ i32.const ตอนที่ฟังก์ชันประกาศ (result i64) ทำให้ค่าที่ค้างอยู่บน stack ตอนจบฟังก์ชันมีชนิดไม่ตรงกับ signature และ validation ไม่ผ่าน
  • สลับลำดับ operand ตอน push ค่าคงที่ขึ้น stack ก่อนเรียกคำสั่งคำนวณ ทำให้ผลลัพธ์ผิดทั้งที่ทุกค่าที่ push มีชนิดถูกต้องแล้ว
  • ลืมว่าฝั่ง JavaScript ต้องรับค่า i64 เป็น BigInt ไม่ใช่ number แล้วเอาไปเปรียบเทียบหรือคำนวณต่อแบบ mix กับ number ตรง ๆ ทำให้เกิด TypeError ตอน runtime

💡 ตัวอย่างจากของจริง

ชุด test suite ของ WABT (WebAssembly Binary Toolkit) มีไฟล์ .wat ที่เขียนมือจำนวนมากซึ่งครอบคลุมทุกชนิดค่า (i32, i64, f32, f64) เพื่อยืนยันว่า encoder/decoder ตีความแต่ละชนิดตรงตาม spec รวมถึงกรณี i64 ที่ฝั่ง JavaScript ต้องแปลงเป็น BigInt

WebAssembly มีชนิดของค่าหลักกี่ชนิด?
ค่าที่คืนกลับชนิด `i64` ของ Wasm กลายเป็นชนิดใดใน JavaScript?
คำสั่งใดที่ push ค่าคงที่แบบทศนิยม (floating-point) ขึ้นไปบน stack?