Diario
Progreso
Sección titulada «Progreso»- Lección 1 — Cadena de herramientas y Cargo
- Lección 2 — Tipos, mutabilidad y expresiones
- Lección 3 — Ownership y movimientos
- Lección 4 — Préstamos y cadenas
- Lección 5 — Structs, enums y pattern matching
- Lección 6 —
Option,Resulty? - Lección 7 — Traits y genéricos
- Lección 8 — Colecciones e iteradores
- Lección 9 — Tiempos de vida (lifetimes)
- Lección 10 — Módulos, crates y workspaces
- Lección 11 —
Box,Rc,Arc,RefCell - Lección 12 — Hilos,
Send/Sync,Mutex, rayon - Lección 13 —
asyncy tokio - Lección 14 — Tests, docs, clippy, fmt
- Lección 15 — Macros,
unsafey FFI
2026-09-13 — Lecciones 1 a 4
Sección titulada «2026-09-13 — Lecciones 1 a 4»- Cadena de herramientas en mi máquina:
rustc 1.94.0,cargo 1.94.0, edición 2024 por defecto paracargo new. - Cada fragmento se compiló antes de escribirse en una lección; los errores del compilador están copiados de la salida real de
rustc(solo se recortaron las largas notas «other types implement this trait»). - El código del curso vive en
code/rust-for-csharp-java:examples/ejecutables y doctestscompile_failensrc/lib.rs, verificados por el workflow de GitHub Rust course examples.
Sorpresas viniendo de C#:
- El desbordamiento de enteros provoca un pánico en las compilaciones de depuración, pero da la vuelta en las compilaciones release — verificado con
255u8 + 1compilado de las dos maneras. C# da la vuelta en ambos casos salvo conchecked. - Clippy marcó
let scores = vec![90, 72, 85, 60];comouseless_vecporque el vector solo se leía como slice — bastaba con un array. - El error del borrow checker para «push mientras se itera» es la versión en tiempo de compilación de
InvalidOperationException: Collection was modified.
Resuelto: ¿comprueba compile_fail,E0382 el código de error? No en stable. Un doctest marcado compile_fail,E0999 alrededor de un uso tras un movimiento (en realidad E0382) seguía pasando con cargo test --doc en 1.94.0 — stable solo comprueba que la compilación falla. El workflow de CI ahora también ejecuta cargo +nightly test --doc, que sí compara los códigos.
2026-09-13 — Lecciones 5 a 8
Sección titulada «2026-09-13 — Lecciones 5 a 8»Cada solución de ejercicio es ahora también un doctest: 41 doctests en total (fragmentos compile-fail más soluciones), todos en verde en 1.94.0.
Errores que los tests detectaron antes de publicar:
- Primero escribí
prices.sort_by(|a, b| a.total_cmp(b))sobrevec![19.99, 5.0, 12.5]. No compila: los literales siguen siendo un{float}sin decidir cuando se comprueban los tipos de la closure (E0599: no method named total_cmp found for reference &{float}). AnotarVec<f64>lo arregla — la lección 8 lo explica ahora. - En la lección 7 afirmé que
cheapestpodía recibir unVec<Box<dyn Priced>>con una restricciónT: Priced + ?Sized. Falso:&[T]exigeT: Sized. La versión que funciona implementaPricedparaBox<dyn Priced>, y eso es lo que el ejercicio muestra (y prueba) ahora. - Clippy rechazó
(1..=5).fold(1, |acc, n| acc * n)en favor de.product()(unnecessary_fold), así que el ejemplo defoldcalcula un par mín/máx — algo que ningún adaptador hace por sí solo.
Sorpresas viniendo de C#:
- Cuando
maindevuelveErr, Rust imprime el error con su formatoDebug(Error: Missing("port")), noDisplay, y termina con el código 1. Vec<f64>::sort()no compila en absoluto (f64no esOrd), mientras que C# y Java ordenan doubles sin rechistar.- El mensaje
E0004para una nueva variante de enum nombra el patrón exacto que falta (&Payment::Crypto { .. } not covered) — mejor que cualquier advertencia de analizador de C# que conozca.
2026-09-13 — Lecciones 9 a 12
Sección titulada «2026-09-13 — Lecciones 9 a 12»76 doctests ahora (stable y nightly), más un workspace real de dos crates para la lección 10 (code/rust-for-csharp-java/l10-workspace) que la CI prueba, analiza y ejecuta. El crate del curso ganó su primera dependencia: rayon, como dev-dependency.
Cosas que primero hice mal:
- En el ejemplo de la lección 9 usé
drop(parser)para mostrar que los tokens sobreviven al parser. Clippy lo rechazó (drop_non_drop): hacer drop de un tipo sin impl deDropno sirve de nada. Una funcióntokenizecuyo parser local muere al final demuestra lo mismo mejor. - Clippy también me enseñó
u64::is_multiple_of(manual_is_multiple_of) en lugar den % d != 0. - Supuse que un
mapde rayon que muta un contador capturado fallaría con un error deSend/Sync. Falla antes: las closures de rayon sonFn, así que esE0594: cannot assign to a captured variable in a Fn closure.
Sorpresas:
- El mensaje de pánico de
RefCellen 1.94 es simplementeRefCell already borrowed; el material más antiguo citaalready borrowed: BorrowMutError. - Escribir
&stren lugar de&'a strcomo tipo de retorno de un método compila sin problema — el error solo aparece en el punto de llamada, cuando intentas conservar dos tokens (E0499). La elisión eligió el lifetime de&mut self. - Un enum recursivo sin
BoxdaE0391(un ciclo en la consulta «needs drop» del compilador) además deE0072. - rayon en esta máquina (Core Ultra 9 285K, 24 núcleos): contar los primos por debajo de 5.000.000 pasó de ~775 ms a ~41 ms, unas 18×.
2026-09-13 — Lecciones 13 a 15, y tres sistemas operativos
Sección titulada «2026-09-13 — Lecciones 13 a 15, y tres sistemas operativos»El curso principal está completo. El código tiene ahora tokio como dev-dependency, dos crates pequeños más (l14-testing, y l15-ffi con un cliente .NET 10), y la CI lo ejecuta todo en Windows, Ubuntu y macOS. El programa C# llama con éxito a la biblioteca Rust en los tres.
Cosas que primero hice mal:
- El test FFI de la lección 15 afirmaba
pricing_sum([19.99, 5.0, 12.5]) == 37.49. La sumaf64real es37.489999999999995; C# había impreso37.49solo por su formatoF2. - Un comentario XML del
.csprojcontenía--release: MSBuild se niega a cargar un proyecto cuyo comentario contiene--. - Escribí que
[LibraryImport]serializaboolcomo unBOOLde 4 bytes por defecto. No tiene ningún valor por defecto: la compilación falla conSYSLIB1051hasta que añades[MarshalAs]. Ese era el comportamiento de[DllImport]. cargo fmt --check --manifest-path …funcionaba en mi máquina (Cargo 1.94) pero fallaba en los runners de CI (Cargo 1.98.1) conFailed to find targets. La CI ahora ejecutacargo fmt --checkdesde la carpeta de cada crate.missing_docs = "warn"en[lints]también se aplica a los tests de integración: cada archivo detests/es su propio crate y necesita una línea//!.- Un doctest de la lección 13 afirmaba que tres esperas concurrentes terminan en menos de 290 ms. Es cierto en mi máquina, pero una aserción de tiempo es un test inestable en runners de CI compartidos, así que el test ahora solo comprueba los resultados.
- Incluso sin aserción de tiempo, un retardo sigue siendo una carrera: en un runner macOS sobrecargado, un intento de 200 ms «tuvo éxito» a pesar de un
timeoutde 50 ms (cuando el runtime se despierta después de ambos plazos,timeoutsondea primero el future, y este ya está listo). Los intentos lentos del ejercicio 2 duran ahora 5 segundos; el test sigue siendo rápido porque se abandonan tras 50 ms.
Sorpresas:
- En Rust asíncrono, un
.awaitolvidado significa que el código nunca se ejecuta — lo contrario de C#, donde la tarea arranca de todos modos. - El error «future cannot be sent between threads safely» no tiene código
E: viene de la restricciónSenddetokio::spawn, no del lenguaje. - La edición 2024 exige
unsafe extern "C"y#[unsafe(no_mangle)]; mucho material FFI antiguo ya no compila tal cual. cargo fmtnunca se había ejecutado en este curso: 30 diferencias de formato en doce lecciones de ejemplos.- Hello world en modo release: unos 130 KB en Windows, 430–460 KB en Linux y macOS (runners de CI, Cargo 1.98.1).
Preguntas abiertas
Sección titulada «Preguntas abiertas»- ¿Cómo se compara
rust-analyzeren RustRover con VS Code para estos ejercicios?