Rust

Equivalencias idiomáticas entre Kotlin y Rust. Kotlin se presenta como referencia en cada concepto.

Modelado de dominio y datos

Cada lenguaje ofrece herramientas distintas para dar forma a un dominio: distinguir qué garantías son del compilador y cuáles son solo convención evita errores de diseño.

Equivalencia desde Kotlin

Clases de valor

Directa

Un newtype tuple struct no añade asignación ni indirección adicional: en tiempo de ejecución EvaluationBudget se representa igual que el i32 que envuelve. El constructor asociado devuelve un Result explícito en vez de lanzar una excepción.

Referencia Kotlin: Declarar un tipo nominal para un dato primitivo y validar su invariante al construirse.

Mecanismo
Newtype tuple struct con un constructor asociado que devuelve Result.
Idea conservada
El newtype no añade una asignación ni una indirección adicional: en tiempo de ejecución EvaluationBudget se representa igual que el i32 que envuelve.
Riesgo de diseño
Hacer público el campo tupla (pub struct EvaluationBudget(pub i32)), lo que permite construir valores sin pasar por new.
Recomendación
Mantén el campo privado y expón solo new devolviendo Result para que el llamador maneje el caso inválido explícitamente.
Convención del curso
Devuelve Result desde new; no entres en pánico dentro del constructor.
Mecanismo del lenguaje
Newtype tuple struct.

Diferencias relevantes

  • La validación devuelve un Result explícito en vez de lanzar una excepción como en Kotlin.
  • El campo interno es privado por convención de módulo, no por una palabra clave dedicada.

new devuelve un Result en vez de lanzar una excepción.

Kotlin
@JvmInline
value class EvaluationBudget(val remaining: Int) {
    init {
        require(remaining > 0) { "El presupuesto debe ser positivo." }
    }
}

val budget = EvaluationBudget(1000) // remaining = 1000
Rust
struct EvaluationBudget(i32);

impl EvaluationBudget {
    fn new(remaining: i32) -> Result<Self, &'static str> {
        if remaining <= 0 {
            return Err("El presupuesto debe ser positivo.");
        }
        Ok(Self(remaining))
    }
}

let budget = EvaluationBudget::new(1000).unwrap(); // remaining = 1000

Fuentes

Equivalencia desde Kotlin

Construcción controlada

Cercana

En Rust, campos privados y constructor asociado expresa la responsabilidad del fixture: Impide crear una edad negativa.

Referencia Kotlin: Un constructor privado y una fábrica validan el invariante.

Mecanismo
campos privados y constructor asociado
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar campos privados y constructor asociado.
Recomendación
Expón el contrato del fixture y usa campos privados y constructor asociado solo para la garantía que realmente ofrece.

Diferencias relevantes

  • La privacidad de construcción y la validación son responsabilidades distintas; declara ambas.
  • La forma idiomática de Rust debe conservarse aunque la sintaxis difiera de Kotlin.

Impide crear una edad negativa.

struct Age(i32); impl Age { fn new(value: i32) -> Option<Self> { (value >= 0).then_some(Self(value)) } }

Fuentes

Equivalencia desde Kotlin

Clases de datos

Cercana

En Rust, struct con derive expresa la responsabilidad del fixture: Modela una medición con igualdad por sus datos.

Referencia Kotlin: data class genera operaciones de valor conocidas.

Mecanismo
struct con derive
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar struct con derive.
Recomendación
Expón el contrato del fixture y usa struct con derive solo para la garantía que realmente ofrece.

Diferencias relevantes

  • No atribuyas copia, destructuración o igualdad estructural a un mecanismo que no las provee.
  • La forma idiomática de Rust debe conservarse aunque la sintaxis difiera de Kotlin.

Modela una medición con igualdad por sus datos.

#[derive(Clone, Debug, PartialEq, Eq)]
struct Measurement { name: String, value: i32 }

Fuentes

Equivalencia desde Kotlin

Singletons

Cercana

En Rust, OnceLock o valor estático expresa la responsabilidad del fixture: Expone una configuración compartida única.

Referencia Kotlin: object declara una instancia única del lenguaje.

Mecanismo
OnceLock o valor estático
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar OnceLock o valor estático.
Recomendación
Expón el contrato del fixture y usa OnceLock o valor estático solo para la garantía que realmente ofrece.

Diferencias relevantes

  • Distingue unicidad por módulo, por proceso y por contenedor de inyección.
  • La forma idiomática de Rust debe conservarse aunque la sintaxis difiera de Kotlin.

Expone una configuración compartida única.

static SETTINGS: OnceLock<u32> = OnceLock::new();

Fuentes

Equivalencia desde Kotlin

Enumeraciones

Cercana

En Rust, enum expresa la responsabilidad del fixture: Representa un estado finito de una tarea.

Referencia Kotlin: enum class declara constantes nombradas y puede contener datos o comportamiento.

Mecanismo
enum
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar enum.
Recomendación
Expón el contrato del fixture y usa enum solo para la garantía que realmente ofrece.

Diferencias relevantes

  • Un enum de constantes y una unión de variantes con datos no son automáticamente equivalentes.
  • La forma idiomática de Rust debe conservarse aunque la sintaxis difiera de Kotlin.

Representa un estado finito de una tarea.

enum Status { New, Done }

Fuentes

Equivalencia desde Kotlin

Jerarquías selladas

Directa

Un enum de Rust agrupa las variantes con datos bajo un solo tipo cerrado. El compilador rechaza un match que no cubra todas las variantes, igual que when sobre una jerarquía sealed en Kotlin.

Referencia Kotlin: Declarar una familia cerrada de alternativas para que el compilador exija manejar cada caso.

Mecanismo
enum con variantes con datos y match exhaustivo.
Idea conservada
El compilador rechaza un match que no cubra todas las variantes del enum, igual que when sobre una jerarquía sealed en Kotlin.
Riesgo de diseño
Agregar un brazo comodín (_ => ...) al match, lo que oculta el error de compilación cuando se agrega una variante nueva.
Recomendación
Evita el brazo comodín _ en un match sobre un enum cerrado del propio crate; deja que el compilador exija cada variante explícitamente.
Convención del curso
No uses un brazo _ en un match sobre un enum cerrado del propio crate.
Mecanismo del lenguaje
enum con datos + match exhaustivo.

Diferencias relevantes

  • Las variantes viven dentro de un único enum en vez de implementar una interfaz sellada separada.
  • match puede desestructurar directamente los campos con nombre de cada variante.

match cubre ambas variantes del enum sin un brazo comodín.

Kotlin
sealed interface SearchResult {
    data class Completed(val bestValue: Double) : SearchResult
    data class Failed(val reason: String) : SearchResult
}

fun describe(result: SearchResult): String = when (result) {
    is SearchResult.Completed -> "Completed(${result.bestValue})"
    is SearchResult.Failed -> "Failed(${result.reason})"
}
Rust
enum SearchResult {
    Completed { best_value: f64 },
    Failed { reason: String },
}

fn describe(result: &SearchResult) -> String {
    match result {
        SearchResult::Completed { best_value } => format!("Completed({best_value})"),
        SearchResult::Failed { reason } => format!("Failed({reason})"),
    }
}

Fuentes

Equivalencia desde Kotlin

Alias de tipos

Cercana

En Rust, type expresa la responsabilidad del fixture: Da un nombre legible a una firma de transformación.

Referencia Kotlin: typealias crea un nombre alternativo, no un nuevo tipo nominal.

Mecanismo
type
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar type.
Recomendación
Expón el contrato del fixture y usa type solo para la garantía que realmente ofrece.

Diferencias relevantes

  • No presentes un alias como una frontera de dominio cuando no cambia la identidad de tipo.
  • La forma idiomática de Rust debe conservarse aunque la sintaxis difiera de Kotlin.

Da un nombre legible a una firma de transformación.

type Transform = fn(i32) -> i32;

Fuentes