Hone logo
Hone
Problems

Generic Data Container

This challenge focuses on implementing a generic struct in Rust. You'll create a reusable data structure that can hold values of any type, demonstrating a fundamental concept in Rust for writing flexible and efficient code. This is crucial for building libraries and applications that can work with diverse data.

Problem Description

Your task is to implement a generic struct named DataContainer<T> in Rust. This struct should be able to hold a single value of any type T.

Key Requirements:

  1. Generic Type T: The DataContainer struct must be generic over a type parameter T.
  2. Single Value Storage: The struct should contain a single field to store a value of type T.
  3. Constructor Method: Implement a constructor method (e.g., new) that takes a value of type T and returns a new DataContainer<T> instance.
  4. Accessor Method: Implement a method (e.g., get) that returns a reference to the stored value.
  5. Mutable Accessor Method: Implement a method (e.g., get_mut) that returns a mutable reference to the stored value.

Expected Behavior:

The DataContainer should be usable with any type, including primitive types, custom structs, and enums. The get method should provide read-only access, while get_mut should allow modification of the contained value.

Edge Cases:

  • Consider how your implementation behaves with different data types (e.g., i32, String, custom structs).
  • Ensure that references returned by get and get_mut are valid for the lifetime of the DataContainer.

Examples

Example 1:

// Assume DataContainer and its methods are defined
let container_int = DataContainer::new(42);
let value_int: &i32 = container_int.get();
println!("Integer value: {}", value_int);

let mut mutable_container_int = DataContainer::new(100);
if let Some(val) = mutable_container_int.get_mut() {
    *val = 200;
}
println!("Modified integer value: {}", mutable_container_int.get());

Output:

Integer value: 42
Modified integer value: 200

Explanation: An integer value 42 is stored in container_int. The get method retrieves a reference to it. A mutable DataContainer is created, and its value is modified from 100 to 200 using get_mut.

Example 2:

// Assume DataContainer and its methods are defined
#[derive(Debug, Clone)]
struct Point {
    x: i32,
    y: i32,
}

let point_value = Point { x: 10, y: 20 };
let container_point = DataContainer::new(point_value.clone()); // Clone to avoid moving ownership if point_value is used later

let retrieved_point: &Point = container_point.get();
println!("Point value: {:?}", retrieved_point);

let mut mutable_container_point = DataContainer::new(Point { x: 5, y: 5 });
if let Some(point) = mutable_container_point.get_mut() {
    point.x = 15;
}
println!("Modified point value: {:?}", mutable_container_point.get());

Output:

Point value: Point { x: 10, y: 20 }
Modified point value: Point { x: 15, y: 5 }

Explanation: A custom Point struct is stored in a DataContainer. get returns a reference to the Point, and get_mut allows modification of its fields.

Example 3: (Handling empty or non-existent data - Note: For this specific challenge, a simpler implementation that always holds a value is expected. However, in more complex scenarios, you might consider Option<T>.)

For this challenge, assume DataContainer always holds a value. The following example demonstrates working with a String.

// Assume DataContainer and its methods are defined
let string_value = String::from("hello generics");
let mut container_string = DataContainer::new(string_value);

let string_ref: &String = container_string.get();
println!("String: {}", string_ref);

if let Some(s) = container_string.get_mut() {
    s.push_str(" world!");
}
println!("Modified String: {}", container_string.get());

Output:

String: hello generics
Modified String: hello generics world!

Explanation: A String is successfully stored and modified within the generic DataContainer.

Constraints

  • The DataContainer struct should contain exactly one field.
  • The constructor new should take ownership of the value it receives.
  • The get method should return an immutable reference (&T).
  • The get_mut method should return a mutable reference (&mut T).
  • The solution should be entirely in Rust.

Notes

  • Think about how Rust's ownership and borrowing rules apply to generic types.
  • The get_mut method might need to return an Option<&mut T> if you were to consider scenarios where the container might be empty, but for this problem, a direct &mut T is sufficient if you assume the container is always initialized.
  • Consider the lifetime of the references returned by get and get_mut. They should be tied to the lifetime of the DataContainer instance.
Loading editor...
rust