// Example 102: Clone vs Copy Traits
//
// Copy: bitwise copy, implicit, for simple stack types (i32, f64, bool, etc.)
// Clone: explicit deep copy via .clone(), for heap types (String, Vec, etc.)
// Approach 1: Copy types โ implicit duplication
fn approach1() {
let x: i32 = 42;
let y = x; // Copy โ both valid
assert_eq!(x, y);
let p = (1.0_f64, 2.0_f64); // tuples of Copy types are Copy
let q = p;
assert_eq!(p, q);
println!("Copy types: x={}, y={}, p={:?}, q={:?}", x, y, p, q);
}
// Approach 2: Clone for heap types
fn approach2() {
let s1 = String::from("hello");
let s2 = s1.clone(); // explicit deep copy
assert_eq!(s1, s2);
let v1 = vec![1, 2, 3];
let v2 = v1.clone();
assert_eq!(v1, v2);
println!("Cloned: s1={}, s2={}, v1={:?}, v2={:?}", s1, s2, v1, v2);
}
// Approach 3: Deriving Copy and Clone for custom types
#[derive(Debug, Clone, Copy, PartialEq)]
struct Point {
x: f64,
y: f64,
}
#[derive(Debug, Clone, PartialEq)]
struct Label {
name: String, // String is not Copy, so Label can't be Copy
position: Point, // Point is Copy
}
fn translate(p: Point, dx: f64, dy: f64) -> Point {
Point { x: p.x + dx, y: p.y + dy }
}
fn approach3() {
// Point is Copy โ no move
let origin = Point { x: 0.0, y: 0.0 };
let moved = translate(origin, 1.0, 2.0);
assert_eq!(origin.x, 0.0); // still valid!
println!("Origin: {:?}, Moved: {:?}", origin, moved);
// Label must be cloned
let label = Label { name: "Start".into(), position: origin };
let label2 = label.clone();
assert_eq!(label, label2);
println!("Label: {:?}, Clone: {:?}", label, label2);
}
fn main() {
println!("=== Approach 1: Copy Types ===");
approach1();
println!("\n=== Approach 2: Clone for Heap Types ===");
approach2();
println!("\n=== Approach 3: Custom Copy/Clone ===");
approach3();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_copy_semantics() {
let x = 42i32;
let y = x;
assert_eq!(x, y);
}
#[test]
fn test_clone_string() {
let s = String::from("test");
let s2 = s.clone();
assert_eq!(s, s2);
// Both are independent
drop(s);
assert_eq!(s2, "test");
}
#[test]
fn test_point_is_copy() {
let p = Point { x: 1.0, y: 2.0 };
let q = p; // Copy
assert_eq!(p, q);
}
#[test]
fn test_label_needs_clone() {
let l = Label { name: "A".into(), position: Point { x: 0.0, y: 0.0 } };
let l2 = l.clone();
assert_eq!(l.name, l2.name);
}
#[test]
fn test_vec_clone_independence() {
let mut v1 = vec![1, 2, 3];
let v2 = v1.clone();
v1.push(4);
assert_eq!(v1.len(), 4);
assert_eq!(v2.len(), 3); // independent
}
}
(* Example 102: Clone vs Copy โ OCaml Implicit Sharing โ Rust Explicit Cloning *)
(* In OCaml, all values are implicitly shared via GC.
There's no distinction between "shallow copy" and "deep copy" at the language level. *)
(* Approach 1: Sharing structured data โ always implicit *)
type point = { x : float; y : float }
let translate p dx dy =
{ x = p.x +. dx; y = p.y +. dy }
let approach1 () =
let origin = { x = 0.0; y = 0.0 } in
let moved = translate origin 1.0 2.0 in
(* origin is still valid โ OCaml creates new record, GC manages old *)
assert (origin.x = 0.0);
assert (moved.x = 1.0);
Printf.printf "Origin: (%.1f, %.1f), Moved: (%.1f, %.1f)\n"
origin.x origin.y moved.x moved.y
(* Approach 2: List sharing โ structural sharing *)
let approach2 () =
let xs = [1; 2; 3] in
let ys = 0 :: xs in (* ys shares the tail with xs *)
assert (List.length xs = 3);
assert (List.length ys = 4);
Printf.printf "xs = %s, ys = %s\n"
(String.concat "; " (List.map string_of_int xs))
(String.concat "; " (List.map string_of_int ys))
(* Approach 3: Deep copy via Marshal (rarely needed) *)
let deep_copy x =
Marshal.from_string (Marshal.to_string x [Marshal.Closures]) 0
let approach3 () =
let data = [| [1; 2]; [3; 4] |] in
let copy = deep_copy data in
assert (data = copy);
Printf.printf "Deep copied array of lists\n"
let () =
approach1 ();
approach2 ();
approach3 ();
Printf.printf "โ All tests passed\n"