Destructuring - Feature 20/41
Destructuring extracts values from data structures using pattern matching. It makes code more concise and readable.
Array Destructuring
let arr = [1, 2, 3, 4, 5]
let [first, second, ...rest] = arr
first // Returns: 1
second // Returns: 2
rest // Returns: [3, 4, 5]
Test Coverage: ✅ tests/lang_comp/pattern_matching/destructuring.rs
Try It in the Notebook
let numbers = [10, 20, 30]
let [a, b, c] = numbers
a // Returns: 10
Expected Output: 10
Tuple Destructuring
let point = (10, 20)
let (x, y) = point
x // Returns: 10
y // Returns: 20
Expected Output: 10, 20
Nested Tuples
let data = ((1, 2), (3, 4))
let ((a, b), (c, d)) = data
a // Returns: 1
d // Returns: 4
Expected Output: 1, 4
Object Destructuring
let person = {
name: "Alice",
age: 30,
city: "Boston"
}
let { name, age } = person
name // Returns: "Alice"
age // Returns: 30
Expected Output: "Alice", 30
Renaming Fields
let user = { id: 1, username: "alice" }
let { id: user_id, username: name } = user
user_id // Returns: 1
name // Returns: "alice"
Expected Output: 1, "alice"
Struct Destructuring
struct Point {
x: f64,
y: f64
}
let p = Point { x: 10.0, y: 20.0 }
let Point { x, y } = p
x // Returns: 10.0
Expected Output: 10.0
Enum Destructuring
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String)
}
let msg = Message::Move { x: 10, y: 20 }
match msg {
Message::Move { x, y } => f"Moving to ({x}, {y})",
Message::Write(text) => f"Writing: {text}",
Message::Quit => "Quitting"
}
// Returns: "Moving to (10, 20)"
Expected Output: "Moving to (10, 20)"
Ignoring Values
Underscore Pattern
let tuple = (1, 2, 3)
let (first, _, last) = tuple
first // Returns: 1
last // Returns: 3
Expected Output: 1, 3
Rest Pattern
let arr = [1, 2, 3, 4, 5]
let [first, ...rest] = arr
first // Returns: 1
rest // Returns: [2, 3, 4, 5]
Expected Output: 1, [2, 3, 4, 5]
Function Parameters
fn print_point({ x, y }) {
print(f"Point at ({x}, {y})")
}
print_point({ x: 10, y: 20 })
// Prints: Point at (10, 20)
Expected Output: Point at (10, 20)
Tuple Parameters
fn distance((x1, y1), (x2, y2)) {
let dx = x2 - x1
let dy = y2 - y1
sqrt(dx * dx + dy * dy)
}
distance((0, 0), (3, 4)) // Returns: 5.0
Expected Output: 5.0
For Loop Destructuring
let points = [(1, 2), (3, 4), (5, 6)]
for (x, y) in points {
print(f"({x}, {y})")
}
// Prints: (1, 2), (3, 4), (5, 6)
Expected Output: (1, 2), (3, 4), (5, 6)
Object Iteration
let users = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 }
]
for { name, age } in users {
print(f"{name} is {age} years old")
}
Expected Output: Alice is 30 years old, Bob is 25 years old
Nested Destructuring
let data = {
user: {
name: "Alice",
contact: {
email: "alice@example.com",
phone: "555-1234"
}
}
}
let { user: { name, contact: { email } } } = data
name // Returns: "Alice"
email // Returns: "alice@example.com"
Expected Output: "Alice", "alice@example.com"
Common Patterns
Swap Variables
let a = 10
let b = 20
[a, b] = [b, a]
a // Returns: 20
b // Returns: 10
Expected Output: 20, 10
Extract First and Last
fn first_and_last(arr) {
let [first, ...middle, last] = arr
(first, last)
}
first_and_last([1, 2, 3, 4, 5]) // Returns: (1, 5)
Expected Output: (1, 5)
Parse Coordinates
let input = "10,20"
let [x_str, y_str] = input.split(",")
let x = parse_int(x_str)
let y = parse_int(y_str)
(x, y) // Returns: (10, 20)
Expected Output: (10, 20)
Config Extraction
fn connect({ host, port = 80, ssl = false }) {
if ssl {
f"https://{host}:{port}"
} else {
f"http://{host}:{port}"
}
}
connect({ host: "example.com" }) // Returns: "http://example.com:80"
Expected Output: "http://example.com:80"
Default Values
fn greet({ name = "Guest", age = 0 }) {
f"Hello {name}, age {age}"
}
greet({ name: "Alice" }) // Returns: "Hello Alice, age 0"
greet({}) // Returns: "Hello Guest, age 0"
Expected Output: "Hello Alice, age 0", "Hello Guest, age 0"
Option Destructuring
let maybe_value = Some(42)
match maybe_value {
Some(value) => f"Got {value}",
None => "No value"
}
// Returns: "Got 42"
Expected Output: "Got 42"
If Let
let result = Some(42)
if let Some(value) = result {
print(f"Value: {value}")
}
// Prints: Value: 42
Expected Output: Value: 42
Result Destructuring
fn divide(a, b) {
if b == 0 {
Err("Division by zero")
} else {
Ok(a / b)
}
}
match divide(10, 2) {
Ok(result) => f"Result: {result}",
Err(error) => f"Error: {error}"
}
// Returns: "Result: 5"
Expected Output: "Result: 5"
Best Practices
✅ Use Destructuring for Clarity
// Good: Clear, concise
let { name, age } = user
// Bad: Verbose
let name = user.name
let age = user.age
✅ Ignore Unused Values
// Good: Explicit
let [first, _, _, last] = arr
// Bad: Misleading names
let [first, dummy1, dummy2, last] = arr
✅ Destructure in Function Parameters
// Good: Clear signature
fn render({ title, body, footer }) {
// ...
}
// Bad: Access inside function
fn render(config) {
let title = config.title
let body = config.body
// ...
}
✅ Use Defaults for Optional Fields
// Good: Safe defaults
fn connect({ host, port = 80 }) {
// ...
}
// Bad: Manual checking
fn connect(config) {
let port = if config.has_key("port") { config.port } else { 80 }
}
Destructuring vs Manual Access
| Method | Code | Readability | Use Case |
|---|---|---|---|
| Destructuring | let { x, y } = point | High | Multiple fields |
| Manual Access | let x = point.x | Medium | Single field |
// Destructuring: Extract multiple values
let { name, age, city } = user
// Manual: Extract single value
let name = user.name
Summary
✅ Feature Status: WORKING ✅ Test Coverage: 100% ✅ Mutation Score: 97%
Destructuring extracts values from data structures in a concise, readable way. It works with arrays, tuples, objects, structs, and enums.
Key Takeaways:
- Arrays:
let [a, b, c] = arr - Tuples:
let (x, y) = tuple - Objects:
let { name, age } = obj - Ignore with
_or...rest - Works in function parameters and for loops
- Use defaults for optional values