Skip to content

Data Types

Rust’s type system is one of the major differences from JavaScript. Let’s explore the various data types in Rust and how they compare to JavaScript.

Type Systems: Static vs Dynamic

JavaScript is dynamically typed, meaning variables can change types at runtime:

let value = 42; // Number
value = "hello"; // Now it's a String
value = true; // Now it's a Boolean

Rust is statically typed, meaning every variable’s type must be known at compile time:

let value = 42; // i32 by default
// value = "hello"; // ❌ Error: mismatched types
// value = true; // ❌ Error: mismatched types

In Rust, you can explicitly annotate types:

let age: u32 = 30;
let name: String = String::from("Alice");
let is_active: bool = true;

Scalar Types

Integers

JavaScript has a single numeric type (Number) for integers and floating-point values, plus BigInt for large integers.

Rust has multiple integer types based on size and signedness:

TypeSize (bits)RangeJS Equivalent
i88-128 to 127Number
u880 to 255Number
i1616-32,768 to 32,767Number
u16160 to 65,535Number
i3232-2,147,483,648 to 2,147,483,647Number
u32320 to 4,294,967,295Number
i6464-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807BigInt
u64640 to 18,446,744,073,709,551,615BigInt
i128128Very large rangeBigInt
u128128Very large rangeBigInt
isizearchDepends on architectureNumber
usizearchDepends on architectureNumber
let a: i32 = 42; // 32-bit signed integer
let b: u64 = 1000000; // 64-bit unsigned integer
let c = 98_222; // Underscores for readability, like 98,222
let d = 0xff; // Hex value
let e = 0o77; // Octal value
let f = 0b1111_0000; // Binary value

In JavaScript, all these would be:

const a = 42; // Number
const b = 1000000; // Number
const c = 98222; // Number
const d = 0xff; // Hex value (255)
const e = 0o77; // Octal value (63)
const f = 0b11110000; // Binary value (240)
const g = 9007199254740992n; // BigInt for numbers > 2^53

Floating-Point Numbers

Rust has two floating-point types:

TypeSize (bits)PrecisionJS Equivalent
f3232Single precisionNumber
f6464Double precisionNumber
let x: f64 = 2.0; // Double-precision float (default)
let y: f32 = 3.0; // Single-precision float

In JavaScript:

const x = 2.0; // Number (always double precision)

Booleans

Both languages have boolean types:

let t: bool = true;
let f: bool = false;
const t = true;
const f = false;

Characters

JavaScript doesn’t have a dedicated character type; single characters are just strings of length 1.

Rust’s char type represents a Unicode scalar value:

let c: char = 'z';
let z: char = 'ℤ';
let heart: char = '❤';

In JavaScript:

const c = 'z'; // String of length 1
const z = ''; // String of length 1 (but 2 bytes in UTF-16)
const heart = ''; // String of length 1 (but 2 bytes in UTF-16)

Compound Types

Tuples

Rust has tuples, which are fixed-length collections of values of different types:

let tup: (i32, f64, u8) = (500, 6.4, 1);
// Destructuring
let (x, y, z) = tup;
println!("y is: {}", y); // 6.4
// Accessing by index
let five_hundred = tup.0; // 500

JavaScript added tuple-like behavior with array destructuring:

// JavaScript doesn't have real tuples, but we can use arrays
const tup = [500, 6.4, 1];
// Destructuring
const [x, y, z] = tup;
console.log(y); // 6.4
// Accessing by index
const fiveHundred = tup[0]; // 500

Arrays

Rust arrays have a fixed length and contain elements of the same type:

// Array with 5 elements of type i32
let a: [i32; 5] = [1, 2, 3, 4, 5];
// Initialize an array with the same value repeated
let b = [3; 5]; // Equivalent to [3, 3, 3, 3, 3]
// Access elements
let first = a[0]; // 1

JavaScript arrays are dynamic and can contain elements of different types:

// JavaScript arrays are dynamic
const a = [1, 2, 3, 4, 5];
a.push(6); // Can add elements
// Can contain mixed types
const mixed = [1, "two", true, { four: 4 }];
// Access elements the same way
const first = a[0]; // 1

For dynamic arrays in Rust, you’d use a Vec (vector), which we’ll cover in the Collections section.

Strings

Strings are a complex topic in Rust, especially coming from JavaScript.

JavaScript Strings

In JavaScript, strings are simple:

const greeting = "Hello, world!";
const name = 'Alice';
const template = `Hello, ${name}!`;
// String methods
const upperName = name.toUpperCase();
const sub = greeting.substring(0, 5); // "Hello"

Rust Strings

Rust has two string types: String and &str:

// String literals are &str (string slices)
let greeting: &str = "Hello, world!";
// String type is growable, heap-allocated
let mut name = String::from("Alice");
name.push_str(" Smith"); // Now "Alice Smith"
// Creating a String from a &str
let s = "initial".to_string();
let s = String::from("initial");
// Concatenation
let hello = String::from("Hello, ");
let world = String::from("world!");
let hello_world = hello + &world; // Note: hello is moved here
// Format macro (like template literals)
let name = "Alice";
let greeting = format!("Hello, {}!", name);

The main differences:

  • &str is immutable and often used for string literals or views into strings
  • String is growable, heap-allocated, and owned
  • Rust strings are UTF-8 encoded, which affects how they’re indexed and manipulated

Type Conversion

JavaScript Type Coercion

JavaScript often performs implicit type conversion:

console.log("5" + 1); // "51" (string)
console.log("5" - 1); // 4 (number)
console.log(5 + true); // 6 (number)

Rust Explicit Conversion

Rust requires explicit conversion:

let x = 5;
// let y = x + "10"; // ❌ Error: cannot add `&str` to `{integer}`
// Explicit conversion
let y = x + 10; // 15
let s = x.to_string() + "10"; // "510"
let z = x + "10".parse::<i32>().unwrap(); // 15

Special Types

The Unit Type

Rust has a unit type (), which represents the absence of a value:

// Functions with no return value implicitly return the unit type
fn do_something() {
println!("Hello");
// Implicitly returns ()
}

JavaScript doesn’t have an equivalent; functions that don’t return anything implicitly return undefined.

The Option Type

Instead of null or undefined, Rust uses Option<T> to represent a value that might be absent:

let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option<i32> = None;
// Using Option requires handling both cases
match some_number {
Some(n) => println!("Got a number: {}", n),
None => println!("No number"),
}

JavaScript equivalent:

const someNumber = 5;
const someString = "a string";
const absentNumber = null;
// Check for null/undefined
if (someNumber !== null && someNumber !== undefined) {
console.log(`Got a number: ${someNumber}`);
} else {
console.log("No number");
}

Type Inference

Both languages can infer types, but Rust’s inference is more sophisticated and happens at compile time:

// Rust infers these types
let x = 5; // i32
let y = 3.0; // f64
let active = true; // bool
// JavaScript also has type inference, but at runtime
let x = 5; // number
let y = 3.0; // number
let active = true; // boolean

Type Aliases

Rust allows you to create type aliases:

type Kilometers = i32;
let distance: Kilometers = 5;

In JavaScript with TypeScript:

type Kilometers = number;
let distance: Kilometers = 5;

Next Steps

Now that you understand Rust’s data types, you’re ready to move on to Functions, where we’ll explore how to define and use functions in Rust compared to JavaScript.