Menu
Coddy logo textTech

Patrón Newtype

Parte de la sección Object Oriented Programming del Journey de Rust de Coddy. Lección 54 de 61.

A veces tienes dos valores del mismo tipo que representan cosas completamente diferentes. El email de un usuario y su password podrían ser ambos valores String, pero intercambiarlos accidentalmente en una llamada a una función sería un error grave. El patrón Newtype resuelve esto creando tipos distintos que envuelven tipos primitivos.

Un newtype es simplemente una estructura de tupla con un solo campo:

struct Password(String);
struct Email(String);

Aunque ambos envuelven un String, el compilador los trata como tipos completamente diferentes. No puedes pasar accidentalmente un Password donde se espera un Email: el compilador detectará el error.

fn send_reset_email(email: Email, password: Password) {
    // ...
}

let email = Email(String::from("user@example.com"));
let pass = Password(String::from("secret123"));

send_reset_email(email, pass);  // Orden correcto impuesto por los tipos
// send_reset_email(pass, email);  // ¡No compilará!

Para access el valor inner, usa .0 ya que es una struct de tupla:

let pass = Password(String::from("secret123"));
println!("Length: {}", pass.0.len());

También puedes añadir métodos a tu newtype, dándole un comportamiento específico de lo que representa, como validación o formato, que no tendría sentido en un String simple.

challenge icon

Desafío

Fácil

¡Construyamos un sistema de registro de user con seguridad de tipos usando el patrón Newtype! Crearás tipos distintos para Username y UserId para evitar mezclarlos accidentalmente, aunque ambos envuelvan valores simples.

Organizarás tu código en dos archivos:

  • user_types.rs: Define dos estructuras newtype public: Username, que envuelve un String, y UserId, que envuelve un u32. Añade un method llamado value a cada una que returns una reference a los datos inner (para Username, devuelve &String; para UserId, devuelve &u32). Esto proporciona access controlado a los valores envueltos.
  • main.rs: Incorpora tu módulo user_types y crea una function llamada display_user que takes un UserId como el primer parameter y un Username como el segundo parameter. La function should print la información del user. Después crea instances de ambos tipos usando los inputs proporcionados y llama a tu function.

La idea clave aquí es que, aunque UserId y Username son envoltorios simples, el compilador los trata como tipos completamente diferentes. ¡No puedes pasar accidentalmente un nombre de user donde se espera un ID!

Tu function display_user should print con este formato:

User #{id}: {username}

Por ejemplo, con los inputs 42 y alice_dev:

User #42: alice_dev

Y con los inputs 1001 y bob_smith:

User #1001: bob_smith

Recibirás dos inputs: el ID del user (parse como u32) y la cadena de username.

REQUIRED OUTPUT FORMAT: [Your translated content here]

Pruébalo tú mismo

mod user_types;

use user_types::{Username, UserId};

// TODO: Crea una función llamada `display_user` que tome:
// - Primer parámetro: UserId
// - Segundo parámetro: Username
// La función debe imprimir: "User #{id}: {username}"
// Usa el método .value() para acceder a los valores internos


fn main() {
    // Leer entrada
    let mut id_input = String::new();
    std::io::stdin().read_line(&mut id_input).expect("Failed to read line");
    let id: u32 = id_input.trim().parse().expect("Invalid number");
    
    let mut username_input = String::new();
    std::io::stdin().read_line(&mut username_input).expect("Failed to read line");
    let username = username_input.trim().to_string();
    
    // TODO: Crea instancias de UserId y Username usando las entradas
    
    // TODO: Llama a display_user con los argumentos correctos
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming

Practica por tu cuenta: Compilador de Rust online