Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros...

332

Transcript of Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros...

Page 1: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...
Page 2: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

0

1

1.1

1.2

1.3

2

2.1

2.2

2.3

3

3.1

3.2

3.3

3.4

3.5

3.6

3.7

3.8

3.9

3.10

4

4.1

4.2

4.3

4.4

4.5

4.6

4.7

4.8

4.9

TabladecontenidoIntroducción

PrimerosPasos

InstalandoRust

¡Hola,mundo!

¡Hola,Cargo!

AprendeRust

ElJuegodelasAdivinanzas

LaCenadelosFilósofos

RustdentrodeotrosLenguajes

RustEfectivo

LaPilayelMontículo

Pruebas

CompilaciónCondicional

Documentación

Iteradores

Concurrencia

ManejodeErrores

FFI

BorrowyAsRef

CanalesdeDistribución

SintaxisySemantica

EnlacesaVariables

Funciones

TiposPrimitivos

Comentarios

if

Ciclos

Pertenencia

ReferenciasyPréstamo

TiemposdeVida

ElLenguajedeProgramacionRust

2

Page 3: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

4.10

4.11

4.12

4.13

4.14

4.15

4.16

4.17

4.18

4.19

4.20

4.21

4.22

4.23

4.24

4.25

4.26

4.27

4.28

4.29

4.30

4.31

4.32

4.33

4.34

4.35

4.36

5

5.1

5.2

5.3

5.4

5.5

5.6

Mutabilidad

Estructuras

Enumeraciones

Match

Patrones

SintaxisdeMétodos

Vectores

CadenasdeCaracteres

Genéricos

Traits

Drop

iflet

ObjetosTrait

Closures

SintaxisUniversaldeLlamadaaFunciones

CratesyMódulos

`const`y`static`

Atributos

Alias`type`

ConversiónentreTipos

TiposAsociados

TipossinTamaño

OperadoresySobrecarga

CoercionesDeref

Macros

ApuntadoresPlanos

`unsafe`

RustNocturno

PluginsdelCompilador

EnsambladorenLinea

Nostdlib

Intrínsecos

ItemsdeLenguaje

EnlaceAvanzado

ElLenguajedeProgramacionRust

3

Page 4: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

5.7

5.8

5.9

5.10

6

7

PruebasdeRendimiento

SintaxisBoxyPatones

PatronesSlice

ConstantesAsociadas

Glosario

InvestigaciónAcadémica

ElLenguajedeProgramacionRust

4

Page 5: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%ElLenguajedeProgramaciónRust

¡Bienvenido!EstelibroteenseñaráacercadelLenguajedeProgramaciónRust.Rustesunlenguajedeprogramacióndesistemasenfocadoentresobjetivos:seguridad,velocidadyconcurrencia.Rustlograestosobjetivossintenerunrecolectordebasura,haciendoloutilparaunnumerodecasosdeusoparaloscualesotroslenguajesnosontanbuenos:embeberenotroslenguajes,programasconrequerimientosespecíficosdetiempoyespacio,escrituradecódigodebajonivel,comocontroladoresdedispositivoysistemasoperativos.Rustmejoraporsobreloslenguajesactualesenestenichoatravésdeunnumerodechequeosentiempodecompilaciónquenoincurrenningunapenalidadentiempodeejecución,eliminandoalmismotiempolascondicionesdecarrera.Rusttambiénimplementa'abstraccionesconcerocosto',abstraccionesquesesientencomolasdeunlenguajedealtonivel.Aunasí,Rustpermitecontrolprecisotalycomounlenguajedebajonivelloharia.

“ElLenguajedeProgramaciónRust”estadivididoensietesecciones.Estaintroduccióneslaprimera.Despuésdeesta:

PrimerosPasos-ConfiguratumaquinaparaeldesarrolloenRust.AprendeRust-AprendeprogramaciónenRustatravésdepequeñosproyectos.RustEfectivo-ConceptosdealtonivelparaescribirexcelentecódigoRust.SintaxisySemántica-CadapiezadeRust,divididaenpequenospedazos.RustNocturno-Característicastodavíanodisponiblesenbuildsestables.Glosario-Referenciadelostérminosusadosenellibro.InvestigaciónAcadémica-LiteraturaqueinfluencioRust.

Despuésdeleerestaintroducción,dependiendodetupreferencia,querrásleer‘AprendeRust’o‘SintaxisySemántica’:‘AprendeRust’siquierescomenzarconunproyectoo‘SintaxisySemántica’,siprefierescomenzarporlomáspequeñoaprendiendounúnicoconceptodetalladamenteantesdemovertealsiguiente.Abundantesenlacescruzadosconectandichaspartes.

Contribuyendo

LosarchivosfuentedeloscualesestelibroesgeneradopuedenserencontradosenGithub:github.com/goyox86/elpr-sources

UnabreveintroducciónaRust¿EsRustunlenguajeenelcualestaríasinteresado?Examinemosunospequeñosejemplosdecódigoquedemuestranalgunasdesusfortalezas.

ElLenguajedeProgramacionRust

5Introducción

Page 6: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

ElconceptoprincipalquehaceúnicoaRustesllamado‘pertenencia’(‘ownership’).Consideraestepequeñoejemplo:

fnmain(){

letmutx=vec!["Hola","mundo"];

}

Esteprogramacreaununavariablellamadax.ElvalordeestavariableesVec<T>,un‘vector’,quecreamosatravésdeunamacrodefinidaenlabibliotecaestandar.Estamacrosellamavec,lasmacrossoninvocadasconun!.TodoestosiguiendounprincipiogeneralenRust:hacerlascosasexplícitas.Lasmacrospuedenhacercosassignificativamentemáscomplejasquellamadasafunciones,esporelloquesonvisualmentedistintas.El!ayudatambiénalanálisissintáctico,haciendolaescrituradeherramientasmásfácil,locualestambiénimportante.

Hemosusadomutparahacerxmutable:EnRustlasvariablessoninmutablespordefecto.Mástardeenesteejemploestaremosmutandoestevector.

Esimportatemencionarquenonecesitamosunaanotacióndetiposaquí:sibienRustesestaticamentetipado,nonecesitamosanotareltipodeformaexplicita.Rustposeeinferenciadetiposparabalancearelpoderdeeltipadoestáticoconlaverbosidaddelasanotacionesdetipos.

Rustprefiereasignacióndememoriadesdelapilaquedesdeelmontículo:xespuestodirectamenteenlapila.Sinembargo,eltipoVec<T>asignaespacioparaloselementosdelvectorenelmontículo.Sinoestasfamiliarizadoconestadistinciónpuedesignorarlaporahoraoecharunvistazo‘LaPilayelMonticulo’.Rustcomounlenguajedeprogramacióndesistemas,tedalahabilidaddecontrolarcomolamemoriaesasignada,perocomoestamoscomenzandonoestanrelevante.

Anteriormentemencionamosquela‘pertenencia’esnuevoconceptoclaveenRust.EnterminologíaRust,xesel‘dueño’delvector.Estosignificaquecuandoxsalgadeámbito,lamemoriaasignadaaelvectorseraliberada.EstoeshechoporelcompiladordeRustdemaneradeterministica,sinlanecesidaddeunmecanismocomounrecolectordebasura.Enotraspalabras,enRust,nohacesllamadasafuncionescomomallocyfreeexplícitamente:elcompiladordeterminademaneraestáticacuandosenecesitaasignaroliberarmemoria,einsertaesasllamadasporti.Erraresdehumanos,peroloscompiladoresnuncaolvidan.

Agreguemosotralíneaanuestroejemplo:

ElLenguajedeProgramacionRust

6Introducción

Page 7: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnmain(){

letmutx=vec!["Hola","mundo"];

lety=&x[0];

}

Hemosintroducidootravariable,y.Enestecaso,yesuna‘referencia’aelprimerelementodeelvector.LasreferenciasenRustsonsimilaresalosapuntadoresenotroslenguajes,peroconchequeosdeseguridadadicionalesentiempodecompilación.Lasreferenciasinteractuanconelsistemadepertenenciaatravésdeel‘prestamo’(‘borrowing’),ellastomanprestadoaloqueapuntan,envezdeadueñarsedeello.Ladiferenciaesquecuandolareferenciasalgadeámbito,lamemoriasubyacentenoseraliberada.Desereseelcasoestaríamosliberandolamismamemoriadosveces,locualesmalo.

Agreguemosunaterceralínea.Dichalínealuceinocenteperocausaunerrordecompilación:

fnmain(){

letmutx=vec!["Hola","mundo"];

lety=&x[0];

x.push("foo");

}

pushesunmetodoenlosvectoresqueagregaunelementoalfinaldelvector.Cuandotratamosdecompilarelprogramaobtenemosunerror:

error:cannotborrow`x`asmutablebecauseitisalsoborrowedasimmutable

x.push("foo");

^

note:previousborrowof`x`occurshere;theimmutableborrowprevents

subsequentmovesormutableborrowsof`x`untiltheborrowends

lety=&x[0];

^

note:previousborrowendshere

fnmain(){

}

^

¡Uff!ElcompiladordeRustalgunasvecespuedeproporcionarerroresbiendetalladosyestavezunadeellas.Comoelerrorloexplica,mientrashacemoslavariablemutablenopodemosllamarapush.Estoesporqueyatenemosunareferenciaaunelementodelvector,y.Mutaralgomientrasexisteunareferenciaaelloespeligroso,porquepodemos

ElLenguajedeProgramacionRust

7Introducción

Page 8: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

invalidarlareferencia.Enestecasoenespecifico,cuandocreamoselvector,solohemosasignadoespacioparadoselementos.Agregaruntercerosignificaríaasignarunnuevosegmentodememoriaparatodosloselementos,copiartodoslosvaloresanterioresyactualizarelapuntadorinternoaesamemoria.Todoesoestabien.Elproblemaesqueynoseriaactualizado,generandoun‘punterocolgante’.Locualestamal.Cualquierusodeyseriaunerrorenestecaso,yelcompiladornoshaprevenidodeello.

Entonces,¿cómoresolvemosesteproblema?Haydosenfoquesquepodríamostomar.Elprimeroeshacerunacopiaenlugardeunareferencia:

fnmain(){

letmutx=vec!["Hola","mundo"];

lety=x[0].clone();

x.push("foo");

}

Rusttienepordefectosemánticademovimiento,entoncessiqueremoshacerunacopiadealgunadata,llamamoselmétodoclone().Enesteejemployyanoesunareferenciaaelvectoralmacenadoenx,sinounacopiadesuprimerelemento,"Hola".Debidoaquenotenemosunareferencianuestropush()funcionaperfectamente.

Sirealmentequeremosunareferencia,necesitamosotraopción:asegurarnosdequenuestrareferenciasalgadeámbitoantesquetratamosdehacerlamutación.Deestamanera:

fnmain(){

letmutx=vec!["Hola","mundo"];

{

lety=&x[0];

}

x.push("foo");

}

Conelparadicionaldellaveshemoscreadounámbitointerno.ysaldrádeámbitoantesquellamemosapush(),entoncesnohayproblema.

Esteconceptodepertenencianoessolobuenoparaprevenirpunteroscolgantes,sinounconjuntoenterodeproblemas,comoinvalidacióndeiteradores,concurrenciaymás.

ElLenguajedeProgramacionRust

8Introducción

Page 9: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%PrimerosPasos

EstaprimeraseccióndellibrotepondráandandoenRustysusherramientas.Primero,instalaremosRust.Después,elclásicoprograma‘HolaMundo’.Finalmente,hablaremosdeCargo,elsistemadeconstrucciónymanejadordepaquetesdeRust.

ElLenguajedeProgramacionRust

9PrimerosPasos

Page 10: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%InstalandoRust

¡ElprimerpasoparausarRustesinstalarlo!ExistenunnúmerodemanerasparainstalarRust,perolamásfácilesusarelscriptrustup.SiestásenLinuxounaMac,todoloquenecesitashaceres(sinescribirlos$s,soloindicaneliniciodecadacomando):

$curl-sf-Lhttps://static.rust-lang.org/rustup.sh|sh

Siestáspreocupadoacercadelainseguridadpotencialdeusarcurl|sh,porfavorcontinúaleyendoyvenuestradeclaración.Siéntetelibredeusarlaversiondedospasosdelainstalaciónyexaminarnuestroscript:

$curl-f-Lhttps://static.rust-lang.org/rustup.sh-O

$shrustup.sh

SiestásenWindows,porfavordescargaelinstaladorde32bitsoelinstaladorde64bitsyejecutalo.

DesintalandoSidecidesqueyanoquieresmásRust,estaremosunpocotristesperoestábien,ningúnlenguajedeprogramaciónesparatodoelmundo.Simplementeejecutaelscriptdedesinstalación:

$sudo/usr/local/lib/rustlib/uninstall.sh

SiusasteelinstaladordeWindowssimplementevuelveaejecutarel.msiyestetedarálaopcióndedesinstalar.

Algunaspersonas,conmuchoderecho,sevenperturbadascuandolesdicesquedebencurl|sh.Básicamente,alhacerlo,estásconfiandoenquelabuenagentequemantieneRustnovaahackeartucomputadoryhacercosasmalas.¡Esoesbueninstinto!SieresunadeesaspersonasporfavorechaunvistazoaladocumentaciónacercadecompilarRustdesdeelcodigofuente,olapáginaoficialdedescargasdebinarios.

¡Ah!,tambiéndebemosmencionarlasplataformassoportadasoficialmente:

Windows(7,8,Server2008R2)Linux(2.6.18omayor,variasdistribuciones),x86andx86-64OSX10.7(Lion)omayor,x86yx86-64

ElLenguajedeProgramacionRust

10InstalandoRust

Page 11: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

NosotrosprobamosRustextensivamenteendichasplataformas,yalgunasotraspocas,comoAndroid.Estassonlasquegarantizanfuncionardebidoaquetienenlamayorcantidaddepruebas.

Finalmente,uncomentarioacercadeWindows.RustconsideraWindowscomounaplataformadeprimeraclaseencuantoarelease,perosisomoshonestos,laexperienciaenWindowsnoestanintegradacomoladeLinux/OSX.¡Estamostrabajandoenello!Sialgonofunciona,esunbug.Porfavorhaznoslosaber.TodosycadaunodeloscommitssonprobadosenWindowsjustocomoencualquierotraplataforma.

SiyatienesRustinstalado,puedesabrirunaconsolayescribir:

$rustc--version

Deberíasverelnúmerodeversión,hashdelcommit,fechadelcommitylafechadecompilación:

rustc1.0.0(a59de37e92015-05-13)(built2015-05-14)

Silohasvisto,Rusthasidoinstaladosatisfactoriamente.¡Felicitaciones!

Esteinstaladortambiéninstalaunacopiadeladocumentaciónlocalmenteparaquepuedasleerlaaúnestandodesconectado.EnsistemasUNIX,/usr/local/share/doc/rusteslalocación.EnWindows,eseneldirectorioshare/doc,dentrodedondeseaquehayasinstaladoRust.

Sino,hayunnúmerodelugaresenlosquepuedesobtenerayuda.ElmásfácileselcanaldeIRC#rustenirc.mozilla.org,alcualpuedesaccederconMibbit.SigueeseenlaceyestaráshablandoconRusteros(atontoapodoqueusamosentrenosotros),yteayudaremos.Otrosexcelentesrecursossonelforodeusuarios,yStackOverflow.

ElLenguajedeProgramacionRust

11InstalandoRust

Page 12: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%¡Hola,mundo!

AhoraquehasinstaladoRust,escribamostuprimerprograma.Estradiciónquetuprimerprogramaencualquierlenguajeseaunoqueimprimaeltexto“¡Hola,mundo!”alapantalla.Lobuenodecomenzarconunprogramatansimpleesqueverificasnosoloqueelcompiladorestainstalado,sinoqueestafuncionando.Imprimirinformaciónalapantallaesunacosamuycomún.

Laprimeracosaquedebemoshacerescrearunarchivoendondeponernuestrocódigo.Amimegustacrearundirectorioproyectosenmidirectoriodeusuarioymantenertodosmisproyectosallí.ARustnoleimportadónderesideelcódigo.

Estollevaencuestiónaotroasuntoquedebemosaclarar:estaguíaasumiráqueposeesunafamiliaridadbásicaconlalineadecomandos.Rustnodemandanadaconrespectoatusherramientasdeediciónodóndevivetucódigo.SiprefieresunIDEalainterfazdelineadecomandos,probablementedeberíasecharunvistazoaSolidOak,odondeseaquelospluginsesténparatuIDEfavorito.Existenunnúmerodeextensionesdecalidadvariadaendesarrolloporlacomunidad.ElequipodetrásdeRusttambiénpublicapluginsparavarioseditores.ConfigurartueditoroIDEescapadelosobjetivosdeéstetutorial,chequealadocumentaciónparatuconfiguraciónespecífica.

Dichoesto,creemosundirectorioennuestrodirectoriodeproyectos.

$mkdir~/proyectos

$cd~/proyectos

$mkdirhola_mundo

$cdhola_mundo

SiestásenWindowsynoestásusandoPowerShell,el~podríanofuncionar.Consultaladocumentacionespecíficaparatuterminalparamayordetalle.

Creemosunnuevoarchivodecódigofuente.Llamaremosmain.rsanuestroarchivo.LosarchivosRustterminanconlaextensión.rs.Siestásusandomásdeunapalabraentunombredearchivo,usaunsubguion:hola_mundo.rsenvezdeholamundo.rs.

Ahoraquetienestuarchivoabiertoescribeestoenel:

fnmain(){

println!("¡Hola,mundo!");

}

Guardaloscambiosenelarchivo,yescribelosiguienteenlaventanadetuterminal:

ElLenguajedeProgramacionRust

12¡Hola,mundo!

Page 13: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$rustcmain.rs

$./main#omain.exeenWindows

¡Hola,mundo!

¡Éxito!Ahoraveamosquehapasadoendetalle.

fnmain(){

}

EstaslineasdefinenunafunciónenRust.Lafunciónmainesespecial:eselprincipiodetodoprogramaRust.Laprimeralíneadice:"Estoydeclarandounafunciónllamadamainlacualnorecibeargumentosynoretornanada."Siexistieranargumentos,estosiríandentrodeparéntesis((and)),ydebidoaquenoestamosretornandonadadeestafunción,podemosomitireltipoderetornocompletamente.Llegaremosaestomásadelante.

Tambiénnotarasquelafunciónestáenvueltaenllaves({and}).Rustrequieredichasllavesdelimitandotodosloscuerposdefunción.Estambiénconsideradobuenestilocolocarlallavedeaperturaenlamismalineadeladeclaracióndelafunción,conunespaciointermedio.

Losiguienteesestalinea:

println!("¡Hola,mundo!");

Estalíneahacetodoeltrabajoennuestropequeñoprograma.Hayunnúmerodedetallesquesonimportantesaquí.Elprimeroesqueestásangradoconcuatroespacios,notabulaciones.Porfavor,configuratueditorainsertarcuatroespaciosconlateclatab.Proveemosalgunasconfiguracionesdeejemploparavarioseditores.

Elsegundopuntoeslaparteprintln!().EstoesllamaraunamacroRustmacro,queescomosehacemetaprogramaciónenRust.Siestofueseencambiounafunción,luciriaasi:println().Paranuestrosefectos,nonecesitamospreocuparnosacercadeestadiferencia.Solosaberquealgunasvecesverás!,yqueestosignificaqueestasllamandoaunamacroenvezdeunafunciónnormal.Rustimplementaprintln!comounamacroenvezdecomounafunciónporbuenasrazones,peroesoesuntópicoavanzado.Unaúltimacosapormencionar:LasmacrosenRustsondiferentesdelasmacrosenC,silashasusado.Noestésasustadodeusarmacros.Llegaremosalosdetalleseventualmente,porahorasimplementedebesconfiarennosotros.

ElLenguajedeProgramacionRust

13¡Hola,mundo!

Page 14: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Acontinuación,"¡Hola,mundo!"esunacadenadecaracteres.Lascadenasdecaracteressonuntópicosorprendentementecomplejoenlenguajesdeprogramacióndesistemas,yéstaconcretamenteesunacadenadecarateres‘asigandaestáticamente’.Sitegustaríaleeracercadeasignacióndememoria,echaunvistazoalapilayelmontículo,peroporahoranonecesitashacerlosinolodeseas.Pasamosestacadenadecaracterescomounargumentoaprintln!quienasuvezimprimelacadenadecaracteresalapantalla.¡Fácil!

Finalmente,lalineaterminaconunpuntoycoma(;).Rustesunlenguajeorientadoaexpresiones,loquesignificaquelamayoríadelascosassonexpresiones,envezdesentencias.El;seusaparaindicarquelaexpresiónhaterminado,yquelasiguienteestálistaparacomenzar.LamayoríadelaslíneasdecódigoenRustterminanconun;.

Finalmente,compilaryejecutarnuestroprograma.Podemoscompilarconnuestrocompiladorrustcpasándoleelnombredenuestroarchivodecódigofuente:

$rustcmain.rs

Estoessimilaragccorclang,siprovienesdeCoC++.Rustemitiráunbinarioejecutable.Puedesverloconls:

$ls

mainmain.rs

OenWindows:

$dir

main.exemain.rs

Haydosarchivos:nuestrocódigofuente,conlaextensión.rs,yelejecutable(main.exeenWindows,mainenlosdemás)

$./main#omain.exeenWindows

Loanteriorimprimenuestrotexto¡Hola,mundo!anuestraterminal.

SiprovienesdeunlenguajedinámicocomoRuby,PythonoJavascript,probablementenoestésacostumbradoaverestosdospasoscomoseparados.Rustesunlenguajecompilado,locualsignificaquepuedescompilartuprograma,dárseloaalguienmás,yéstenonecesitatenerRustinstalado.Silesdasaalguienunarchivo.rbo.pyo.js,estenecesitatenerunaimplementacióndeRuby/Python/JavaScript,perosólonecesitasuncomandoparaambos,compilaryejecutartuprograma.Todoesacercadebalanceentreventajas/desventajaseneldiseñodelenguajes,yRusthaelegido.

ElLenguajedeProgramacionRust

14¡Hola,mundo!

Page 15: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Felicitaciones,hasescritooficialmenteunprogramaRust.¡EsoteconvierteenunprogramadorRust!Bienvenido.

Acontinuaciónmegustaríapresentarteotraherramienta,Cargo,elcualesusadoparaescribirprogramasRustparaelmundoreal.Solousarrustcestabienparacosassimples,peroamedidaquetuproyectocrece,necesitarásalgoqueteayudeaadministrartodaslasopcionesqueestetiene,asícomohacerfácilcompartirelcodigoconotraspersonasyproyectos.

ElLenguajedeProgramacionRust

15¡Hola,mundo!

Page 16: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Hola,Cargo!

CargoesunaherramientaquelosRusterosusancomoayudaparaadministrarsusproyectosRust.Cargoestaactualmenteenestadopre-1.0,ydebidoaelloestodavíauntrabajoenproceso.SinembargoyaeslosuficientementebuenoparamuchosproyectosRust,yseasumequelosproyectosRustusaranCargodesdeelprincipio.

Cargoadministratrescosas:lacompilacióndetucódigo,descargadelasdependenciasquetucódigonecesita,ylacompilacióndedichasdependencias.Enprimerainstanciatucódigonotendráningunadependencia,esporelloqueestaremosusandosololaprimerapartedelafuncionalidaddeCargo.Eventualmente,agregaremosmas.DebidoaquecomenzamosusandoCargodesdeelprincipioserafácilagregardespués.

SihasinstaladoRustatravésdelosinstaladoresoficialesentoncesdeberíastenerCargo.SihasinstaladoRustdealgunaotramanera,podríasecharunvistazoaelREADMEdeCargoparainstruccionesespecificasacercadecomoinstalarlo.

MigrandoaCargoConvirtamosHolaMundoaCargo.

ParaCarguificarnuestroproyecto,necesitamosdoscosas:CrearunarchivodeconfiguraciónCargo.toml,ycolocarnuestroarchivodecódigofuenteenellugarcorrecto.Hagamosesaparteprimero:

$mkdirsrc

$mvmain.rssrc/main.rs

Notaquedebidoaqueestamoscreandounejecutable,usamosmain.rs.Siquisiéramoscrearunabiblioteca,deberíamosusarlib.rs.Locacionespersonalizadasparaelpuntodeentradapuedenserespecificadasconunaclave[[[lib]]or[[bin]]]crates-customenelarchivoTOMLdescritoacontinuación.

Cargoesperaquetusarchivosdecódigofuenteresidaneneldirectoriosrc.Estodejaelnivelraízparaotrascosas,comoREADMEs,informacióndelicencias,ytodoaquellonorelacionadocontucódigo.Cargonosayudaamantenernuestrosproyectosagradablesyordenados.Unlugarparatodo,ytodoensulugar.

Acontinuación,nuestroarchivodeconfiguración:

$editorCargo.toml

ElLenguajedeProgramacionRust

16¡Hola,Cargo!

Page 17: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Aseguratetetenerestenombrecorrecto:necesitaslaCmayuscula!

Colocaestodentro:

[package]

name="hola_mundo"

version="0.0.1"

authors=["Tunombre<[email protected]>"]

EstearchivoestaenformatoTOML.Dejemosqueseaelmismoquienseexplique:

ElobjetivodeTOMLesserunformatodeconfiguraciónminimofacildeleerdebidoaunasemánticaobvia.TOMLestadiseñadoparamapeardeformain-ambiguaaunatablahash.TOMLdeberíaserfácildeconvertirenestructurasdedatosenunaampliavariedaddelenguajes.

TOMLesmuysimilaraINI,peroconalgunasbondadesextra.

Unavezquetengasestearchivoessulugar,deberíamosestarlistosparacompilar!Pruebaesto:

$cargobuild

Compilinghola_mundov0.0.1(file:///home/tunombre/proyectos/hola_mundo)

$./target/debug/hola_mundo

Hola,mundo!

Bam!Construimosnuestroproyectoconcargobuild,yloejecutamoscon./target/debug/hola_mundo.Podemoshacerlosdospasosenunoconcargorun:

$cargorun

Running`target/debug/hola_mundo`

Hola,mundo!

Nótesequenoreconstruimoselproyectoestavez.Cargodeterminoquenohabíamoscambiadoelarchivodecódigofuente,asíquesimplementeejecutoelbinario.Sihubiéremosrealizadounamodificación,deberíamoshaberlovistohaciendolosdospasos:

$cargorun

Compilinghola_mundov0.0.1(file:///home/tunombre/proyectos/hola_mundo)

Running`target/debug/hola_mundo`

Hola,mundo!

ElLenguajedeProgramacionRust

17¡Hola,Cargo!

Page 18: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Estononoshaaportadomuchoporencimadenuestrosimpleusoderustc,peropiensaenelfuturo:cuandonuestrosproyectossehaganmascomplicados,necesitaremoshacermascosasparalograrquetodaslaspartescompilencorrectamente.ConCargo,amedidaquenuestroproyectocrece,simplementeejecutamoscargobuild,ytodofuncionaradeformacorrecta.

Cuandonuestroproyectoestafinalmentelistoparalaliberacion,puedesusarcargobuild--releaseparacompilarloconoptimizaciones.

TambiénhabrasnotadoqueCargohacreadounarchivonuevo:Cargo.lock.

[root]

name="hola_mundo"

version="0.0.1"

EstearchivoesusadoporCargoparallevarelcontroldelasdependenciasusadasentuaplicación.Porahora,notenemosninguna,yestaunpocodisperso.Nuncadeberíasnecesitartocarestearchivoportucuenta,solodejaaCargomanejarlo.

Esoestodo!Hemosconstruidosatisfactoriamentehola_mundoconCargo.Aunquenuestroprogramaseasimple,estausandogranpartedelasherramientasrealesqueusarasporelrestodetucarreraconRust.PuedesasumirqueparacomenzarvirtualmentecontodoproyectoRustharáslosiguiente:

$gitclonealgunaurl.com/foo

$cdfoo

$cargobuild

UnProyectoNuevoNotienesquepasarportodoeseprocesocompletocadavezquequierascomenzarunproyectonuevo!Cargoposeelahabilidaddecrearundirectorioplantillaenelcualpuedescomenzaradesarrollarinmediatamente.

ParacomenzarunproyectonuevoconCargo,usamoscargonew:

$cargonewhola_mundo--bin

Estamospasando--binporqueestamoscreandounprogramabinario:siestuviéramoscreandounabiblioteca,loomitiríamos.

EchemosunvistazoaloqueCargohageneradoparanosotros:

ElLenguajedeProgramacionRust

18¡Hola,Cargo!

Page 19: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$cdhola_mundo

$tree.

.

├──Cargo.toml

└──src

└──main.rs

1directory,2files

Sinotieneselcomandotreeinstalado,probablementepodríasobtenerlomedianteelmanejadordepaquetesdetudistribución.Noesnecesario,peroesciertamenteútil.

Estoestodoloquenecesitasparacomenzar.PrimeroveamosnuestroCargo.toml:

[package]

name="hola_mundo"

version="0.0.1"

authors=["TuNombre<[email protected]>"]

Cargoarellenadoestearchivoconvalorespordefectobasadoenlosargumentosqueleproporcionasteytuconfiguraciónglobalgit.PodriasnotartambienqueCargohainicializadoeldirectoriohola_mundocomounrepositoriogit.

Aquiestaelcontenidodesrc/main.rs:

fnmain(){

println!("Hola,mundo!");

}

Cargohageneradoun"Hola,mundo!"paranosotros,yaestaslistoparaempezaracodear.Cargoposeesupropiaguialacualcubretodassuscaracterísticasconmuchamasprofundidad.

Ahoraquehemosaprendidolasherramientas,comencemosenrealidadaaprendermasdeRustcomolenguaje.EstoeslabásequeteservirábienporelrestodetutiempoconRust.

Tienesdosopciones:Sumergirteenunproyectocon‘AprendeRust’,ocomenzardesdeelfondoytrabajarhaciaarribacon‘SintaxisySemántica’.Programadoresdesistemasmasexperimentadosprobablementepreferiran‘AprendeRust’,mientrasqueaquellosprovenientesdelenguajesdinamicospodriantambiendisfrutarlo.Gentediferenteaprendediferente!Escojeloquefuncionemejorparati.

ElLenguajedeProgramacionRust

19¡Hola,Cargo!

Page 20: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%AprendeRust

¡Bienvenido!EstaseccióntieneunospocostutorialesqueteenseñaránRustatravésdelaconstruccióndeproyectos.Obtendrásunavisióngeneral,perotambiénleecharemosunvistazoalosdetalles.

Siprefieresunaexperienciamásalestilo‘deabajohaciaarriba’,echaunvistazoaSintaxisySemántica.

ElLenguajedeProgramacionRust

20AprendeRust

Page 21: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%JuegodeAdivinanzas

Paranuestroprimerproyecto,implementaremosunproblemaclásicodeprogramaciónparaprincipiantes:unjuegodeadivinanzas.Comofuncionaeljuego:Nuestroprogramageneraraunnumeroenteroaleatorioentreunoycien.Nospediraqueintroduzcamosunacorazonada.Despuesdehaberproporcionadonuestronumero,estenosdirásiestuvimosmuypordebajoymuyporencima.Unavezqueadivinemoselnumerocorrecto,nosfelicitara.Suenabien?

ConfiguraciónInicialCreemosunnuevoproyecto.Andaatudirectoriodeproyectos.RecuerdascomocreamosnuestraestructuradedirectoriosyunCargo.tomlparahola_mundo?Cargoposseuncomandoquehaceesopornosotros.Probemoslo:

$cd~/proyectos

$cargonewadivinanzas--bin

$cdadivinanzas

Pasamoselnombredenuestroproyectoacargonew,juntoconelflag--bin,debidoaqueestamoscreandounbinario,envezdeunabiblioteca.

EchaunvistazoalCargo.tomlgenerado:

[package]

name="adivinanzas"

version="0.1.0"

authors=["TuNombre<[email protected]>"]

Cargoobtieneestainformacióndetuentorno.Sinoestacorrecta,corrigela.

Finalmente,Cargohageneradoun‘Hola,mundo!’paranosotros.Echaunvistazoasrc/main.rs:

fnmain(){

println!("Hello,world!");

}

TratemosdecompilarloqueCargonoshaproporcionado:

ElLenguajedeProgramacionRust

21ElJuegodelasAdivinanzas

Page 22: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$cargobuild

Compilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

Excelente!Abretusrc/main.rsotravez.Estaremosescribiendotodonuestrocodigoenestearchivo.

Antesdecontinuar,dejamemostrarteuncomandomasdeCargo:run.cargorunesunaespeciedecargobuild,peroconladiferenciadequetambienejecutaelbinarioproducido.Probemoslo:

$cargorun

Compilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

Running`target/debug/adivinanzas`

Hola,mundo!

Grandioso!Elcomandorunesmuyútilcuandonecesitasiterarrapidoenunproyecto.Nuestrojuegoesunodeesosproyectos,necesitaremosprobarrapidamentecadaiteraciónantesdemovernosalasiguiente.

ProcesandounIntentodeAdivinanzaProbemoslo!Laprimeracosaquenecesitamoshacerparanuestrojuegodeadivinanzasespermitiranuestrojugadoringresarunintentodeadivinanza.Colocaestoentusrc/main.rs:

usestd::io;

fnmain(){

println!("Adivinaelnumero!");

println!("Porfavorintroducetucorazonada.");

letmutcorazonada=String::new();

io::stdin().read_line(&mutcorazonada)

.ok()

.expect("Falloalleerlinea");

println!("Tucorazonadafue:{}",corazonada);

}

Hayunmontonaqui!Tratemosdeiratravesdeello,piezaporpieza.

ElLenguajedeProgramacionRust

22ElJuegodelasAdivinanzas

Page 23: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::io;

Necesitaremosrecibirentradadelusuario,paraluegoimprimirelresultadocomosalida.Debidoaestonecesitamoslabibliotecaiodelabibliotecaestandar.Rustsoloimportaunaspocascosasparatodoslosprogramas,esteconjuntodecosassedenomina‘preludio’.Sinoestaenelpreludiotendrásquellamarlodirectamenteatravesdeuse.

fnmain(){

Comohasvistoconanterioridad,lafunciónmain()eselpuntodeentradaatuprograma.Lasintaxisfndeclaraunanuevafunción,los()sindicanquenohayargumentosy{comienzaelcuerpodelafunción.Debidoaquenoincluimosuntipoderetorno,seasumeser()unatuplavacía.

println!("Adivinaelnumero!");

println!("Porfavorintroducetucorazonada.");

Anteriormenteaprendimosqueprintln!()esunamacroqueimprimeunacadenadecaracteresalapantalla.

letmutcorazonada=String::new();

Ahoranosestamosponiendointeresantes!Hayunmontóndecosaspasandoenestapequeñalinea.Laprimeracosasanotaresqueesunasentencialet,usadaparacrearvariables.Tienelaforma:

letfoo=bar;

Estocrearaunanuevavariablellamadafoo,ylaenlazaraalvalorbar.Enmuchoslenguajes,estoesllamadouna‘variable’perolasvariablesdeRusttienenunpardetrucosbajolamanga.

Porejemplo,sonimmutablespordefecto.Esporelloquenuestroejemplousamut:estohaceunbindingmutable,envezdeinmutable.letnosolotomaunnombredelladoizquierdo,letaceptaun‘patrón’.Usaremoslospatronesunpocomastarde.Essuficienteporahorausar:

letfoo=5;//inmutable.

letmutbar=5;//mutable

ElLenguajedeProgramacionRust

23ElJuegodelasAdivinanzas

Page 24: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Ah,//iniciauncomentario,hastaelfinaldelalinea.Rustignoratodoencomentarios

Entoncessabemosqueletmutcorazonadaintroduciráunbindingmutablellamadocorazonada,perotenemosqueveralotroladodel=parasaberaqueestasiendoasociado:String::new().

Stringesuntipodecadenadecaracter,proporcionadoporlabibliotecaestandar.UnStringesunsegmentodetextocodificadoenUTF-8capazdecrecer.

Lasintaxis::new()usa::porqueesuna‘funciónasociada’deuntipoparticular.EsdecirestaasociadaconStringensimismo,envezdeconunainstaciaenparticulardeString.Algunoslenguajesllamanaestoun‘metodoestatico’.

Estafuncionesllamadanew(),porquecreaunnuevoStringvacio.Encontrarasunafunciónnew()enmuchostipos,debidoaqueesunnombrecomúnparalacreacióndeunnuevovalordealguntipo.

Continuemos:

io::stdin().read_line(&mutcorazonada)

.ok()

.expect("Fallolecturadelinea");

Otromonton!Vallamospiezaporpieza.Laprimeralineatienedospartes.Heaquilaprimera:

io::stdin()

Recuerdascomousamosuseenstd::ioenlaprimeralineadenuestroprograma?Ahoraestamosllamandounafunciónasociadaenstd::io.Denohaberusadousestd::io,pudimoshaberescritoestalineacomostd::io::stdin().

Estafunciónenparticularretornaunhandlealaentradaestándardetuterminal.Masespecificamente,unstd::io::Stdin.

Lasiguienteparteusaradichohandleparaobtenerentradadelusuario:

.read_line(&mutcorazonada)

Aqui,llamamoselmetodoread_line()ennuestrohandle.Losmetodossonsimilaresalasfuncionesasociadas,perosoloestandisponiblesenunainstanciaenparticulardeuntipo,envezdeeneltipoensi.Tambiénestamospasandounargumentoaread_line():&mutcorazonada.

ElLenguajedeProgramacionRust

24ElJuegodelasAdivinanzas

Page 25: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Recuerdascuandocreamoscorazonada?Dijimosqueeramutable.Sinembargoread_linenoaceptaunStringcomoargumento:aceptaun&mutString.Rustposeeunacaracteristicallamada‘referencias’(‘references’),lacualpermitetenermultiplesreferenciasaunapiezadedata,deestamanerasereducelanecesidaddecopiado.Lasreferenciassonunacaracteristicacompleja,debidoaqueunodelospuntosdeventamasfuertesdeRustesacercadecuanfácilyseguroesusarreferencias.Porahoranonecesitamossabermuchodeesosdetallesparafinalizarnuestroprograma.Todoloquenecesitamossaberporelmomentoesquealigualquelosbindingsletlasreferenciassoninmutablespordefecto.Comoconsecuencianecesitamosescribir&mutcorazonadaenvezde&corazonada.

Porqueread_line()aceptaunareferenciamutableaunacadenadecaracteres.Sutrabajoestomarloqueelusuarioingresaenlaentradaestandar,ycolocarloenunacadenadecaracteres.Debidoaellotomadichacadenacomoargumento,ydebidoaquedebedeagregarlaentradadelusuario,estenecesitasermutable.

Todavianohemosterminadoconestalinea.Sibienesunasolalineadetexto,essololaprimerapartedeunalinealogicadecódigocompleta:

.ok()

.expect("Fallolecturadelinea");

Cuandollamasaunmetodoconlasintaxis.foo()puedesintroducirunsaltodelineayotroespacio.Estoteayudaadividirlineaslargas.Pudimoshaberescrito:

io::stdin().read_line(&mutcorazonada).ok().expect("Fallolecturadelinea");

Peroesoesmasdifícildeleer.Asíquelohemosdivididoentreslineasparatresllamadasametodo.Yahemoshabladoderead_line(),peroqueacercadeok()yexpect()?Bueno,yamencionamosqueread_line()colocalaentradadelusuarioenel&mutStringqueleproprocionamos.Perotambienretornaunvalor:enestecasounio::Result.RustposeeunnumerodetiposllamadosResultensubibliotecaestandar:unResultgenerico,yversionesespecificasparasub-bibliotecas,comoio::Result.

ElpropositodeesosResultescodificarinformacióndemanejodeerrores.ValoresdeltipoResulttienenmetodosdefinidosenellos.Enestecasoio::Resultposeeunmetodook(),quesetraduceen‘queremosasumirqueestevaloresunvalorexitoso.Sino,descartalainformaciónacercadelerror’.Porquedescartarlainformaciónacercadelerror?,paraunprogramabásico,queremossimplementeimprimirunerrorgenerico,cualquierproblemaquesignifiquequenopodamoscontinuar.Elmetodook()retornaunvalorquetieneotrometododefinitoenel:expect().Elmetodoexpect()tomaelvalorenelcuales

ElLenguajedeProgramacionRust

25ElJuegodelasAdivinanzas

Page 26: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

llamadoysinoesunvalorexitoso,hacepanicopanic!conunmensajequelehemosproporcionado.Unpanic!comoestecausaraqueelprogramatengaunasalidaabrupta(crash),mostrandodichomensaje.

Siquitamoslasllamadasaesosdosmetodos,nuestroprogramacompilara,peroobtendremosunaadvertencia:

$cargobuild

Compilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

src/main.rs:10:5:10:44warning:unusedresultwhichmustbeused,#[warn(unused_must_use)]onbydefault

src/main.rs:10io::stdin().read_line(&mutcorazonada);

^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

RustnosadviertequenohemosusadoelvalorResult.Estaadvertenciavienedeunaanotaciónespecialquetieneio::Result.Rustestatratandodedecirtequenohasmanejadounposibleerror.Lamaneracorrectadesuprimirelerrores,enefectoescribirelcódigoparaelmanejodeerroes.Porsuerte,sisoloqueremosterminarlaejecucióndelprogramadehaberunproblema,podemosusarestosdospequeñosmetodos.Sipudieramosrecuperarnosdelerrordealgunamanera,hariamosalgodiferente,perodejemosesoparaunproyectofuturo.

Solonosquedaunalineadeesteprimerejemplo:

println!("Tucorazonadafue:{}",corazonada);

}

Estalineaimprimelacadenadecaracteresenlaqueguardamosnuestraentrada.Los{}ssonmarcadoresdeposición,esporelloquepasamosadivinanzacomoargumento.Dehaberhabidomultiples{}s,debiamoshaberpasadomultiplesargumentos:

letx=5;

lety=10;

println!("xyy:{}y{}",x,y);

Fácil.

Decualquiermodo,eseeseltour.Podemosejecutarloconcargorun:

ElLenguajedeProgramacionRust

26ElJuegodelasAdivinanzas

Page 27: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$cargorun

Compilingguessing_gamev0.1.0(file:///home/tu/proyectos/adivinanzas)

Running`target/debug/adivinanzas`

Adivinaelnumero!

Porfavorintroducetucorazonada.

6

Tucorazonadafue:6

Enhorabuena!Nuestraprimerapartehaterminado:podemosobtenerentradadeltecladoeimprimirladevuelta.

GenerandounnumerosecretoAcontinuaciónnecesitamosgenerarunnumerosecreto.Rusttodavíanoincluyeunafuncionalidaddenumerosaleatoriosenlabibliotecaestándar.Sinembargo,elequipodeRustproveeuncraterand.Un‘crate’esunpaquetedecódigoRust.Nosotroshemosestadoconstruyendoun‘cratebinaro’,elcualesunejecutable.randesun‘cratebiblioteca’,quecontienecodigoaserusadoporotrosprogramas.

UsarcratesexternosesdondeCargorealmentebrilla.Antesquepodamosescribircódigoquehagausoderand,debemosmodificarnuestroarchivoCargo.toml.Abrelo,yagregaestaslineasalfinal:

[dependencies]

rand="0.3.0"

Lasección[dependencies]deCargo.tomlescomolasección[package]:todoloquelesigueespartedeella,hastaquelasiguienteseccióncomience.Cargousalaseccióndedependenciasparasaberencualescratesexternosdependemos,asicomolasversionesrequeridas.Enestecasohemosusadolaversión0.3.0.CargoentiendeVersionadoSemantico,queesunestandarparalasescrituradenumerosdeversión.Siquisieramosusarlaultimaversionpodriamoshaberusado*ounrangodeversiones.LadocumentacióndeCargocontienemasdetalles.

Ahora,sincambiarnadaennuestrocódigo,construyamosnuestroproyecto:

ElLenguajedeProgramacionRust

27ElJuegodelasAdivinanzas

Page 28: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$cargobuild

Updatingregistry`https://github.com/rust-lang/crates.io-index`

Downloadingrandv0.3.8

Downloadinglibcv0.1.6

Compilinglibcv0.1.6

Compilingrandv0.3.8

Compilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

(Podriasverversionesdiferentes,porsupuesto.)

Unmontóndesalidamas!Ahoraquetenemosunadependenciaexterna,Cargodescargadelregistrolasultimasversionesdetodo,locualpuedecopiardatosdesdeCrates.io.Crates.ioesdondelaspersonasdelecosistemaRustpublicansusproyectosopensourceparaqueotroslosusen.

Despuesdeactualizarelregistro,Cargochequeanuestrasdependencias(en[dependencies])ylasdescargadenotenerlastodavía.Enestecasosolodijimosquequeriamosdependerenrand,ytambienobtuvimosunacopiadelibc.Estoesdebidoaqueranddependeasuvezdelibcparafuncionar.Despuesdedescargarlasdependencias,Cargolascompila,paradespuescompilarnuestrocódigo.

Siejecutamoscargobuild,obtendremosunasalidadiferente:

$cargobuild

Asies,nohaysalida!Cargosabequenuestroproyectohasidoconstruido,asicomotodassusdependencias,asiquenonayrazónparahacertodoelprocesootravez.Sinnadaquehacer,simplementeterminalaejecucion.Siabrimossrc/main.rsotravez,hacemosuncambiotrivial,salvamosloscambios,solamenteveriamosunalinea:

$cargobuild

Compilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

Entonces,lehemosdichoaCargoquequeriamoscualquierversión0.3.xderand,yestedescargolaultimaversiónparaelmomentodelaescrituradeestetutorial,v0.3.8.Peroquepasacuandolasiguienteversiónv0.3.9seapublicadaconunimportantebugfix?Sibienrecibirbugfixesesimportante,quepasasi0.3.9contieneunaregresionquerompenuestrocodigo?

LarespuestaaesteproblemaeselarchivoCargo.lock,archivoqueencontrarasentudirectoriodeproyecto.Cuandoconstruyestuproyectoporprimeravez,cargodeterminatodaslasversionesquecoincidencontuscriteriosylasescribeenelarchivoCargo.lock.Cuandoconstruyestuproyectoenelfuturo,CargonotaraqueunarchivoCargo.lock

ElLenguajedeProgramacionRust

28ElJuegodelasAdivinanzas

Page 29: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

existe,yusaralasversionesespecificadasenelmismo,envezdehacertodoeltrabajodedeterminarlasversionesotravez.Estotepermitetenerunaconstrucciónreproducibledemaneraautomatica.Enotraspalabras,nosquedaremosen0.3.8hastaquesubamosdeversiondemaneraexplicita,deigualmaneraloharálagenteconlaquehemoscompartidonuestrocódigo,graciasalarchivoCargo.lock.

Peroquepasacuandoqueremosusarv0.3.9?Cargoposeeotrocomando,update,quesetraduceen‘ignoraelbloqueoydeterminatodaslasultimasversionesquecoincidanconloquehemosespecficado.Defuncionaresto,escribeesasversionesalarchivodebloqueoCargo.lock’.Pero,pordefecto,Cargosolobuscaraversionesmayoresa0.3.0ymenoresa0.4.0.Siqueremosmovernosa0.4.x,necesitariamosactualizarelarchivoCargo.tomldirectamente.Cuandolohacemos,lasiguentevezqueejecutemoscargobuild,Cargoactualizaraelindiceyre-evaluaranuestrosrequerimentosacercaderand.

HaymuchomasquedeciracercadeCargoysuecosistema,peroporahora,esoestodoloquenecesitamossaber.Cargohacerealmentefácilreusarbibliotecas,ylosRusterostiendenaescribirproyectospequenosloscualesestanconstruidosporunconjuntodepaquetesmaspequeños.

Hagamosusoahoraderand.Heaquinuestrosiguientepaso:

externcraterand;

usestd::io;

userand::Rng;

fnmain(){

println!("Adivinaelnumero!");

letnumero_secreto=rand::thread_rng().gen_range(1,101);

println!("Elnumerosecretoes:{}",numero_secreto);

println!("Porfavorintroducetucorazonada.");

letmutcorazonada=String::new();

io::stdin().read_line(&mutcorazonada)

.ok()

.expect("Falloalleerlinea");

println!("Tucorazonadafue:{}",corazonada);

}

ElLenguajedeProgramacionRust

29ElJuegodelasAdivinanzas

Page 30: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Laprimeracosaquehemoshechoescambiarlaprimeralinea.Ahoradiceexterncraterand.Debidoaquedeclaramosrandennuestrasección[dependencies],podemosusarexterncrateparahacerlesaberaRustqueestaremoshaciendousoderand.Estoesequivalenteaunuserand;,demaneraquepodamoshacerusodeloqueseadentrodelcraterandatravesdelprefijorand::.

Después,hemosagregadootralineause:userand::Rng.Enunosmomentosestaremoshaciendousodeunmetodo,yestorequierequeRngestedisponibleparaquefuncione.Laideabasicaeslasiguiente:losmetodosestandentrodealgollamado‘traits’(Rasgos),yparaqueelmetodofuncionenecesitaqueeltraitestedisponible.ParamayoresdetallesdirigetealasecciónRasgos(Traits).

Haydoslineasmasenelmedio:

letnumero_secreto=rand::thread_rng().gen_range(1,101);

println!("Elnumerosecretoes:{}",numero_secreto);

Hacemosusodelafunciónrand::thread_rng()paraobtenerunacopiadelgeneradordenumerosaleatorios,elcualeslocalalhilodeejecucionenelcualestamos.Debidoaquehemoshechodisponiblearand::Rngatravesdeuserand::Rng,estetieneunmetodogen_range()disponible.Estemetodoaceptadosargumentos,ygeneraunnumeroaleatorioentreestos.Esinclusivoenellimiteinferior,peroesexclusivoenellimitesuperior,poresonecesitamos1y101paraobtenerunnumeroentreunoycien.

Lasegundalineasoloimprimeelnumerosecreto.Estoesútilmietrasdesarrollamosnuestroprograma,demaneratalquepodamosprobarlo.Estaremoseliminandoestalineaparalaversionfinal.Noesunjuegosiimprimelarespuestajustocuandoloinicias!

Tratadeejecutarelprogramaunaspocasveces:

ElLenguajedeProgramacionRust

30ElJuegodelasAdivinanzas

Page 31: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$cargorun

Compilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

Running`target/debug/adivinanzas`

Adivinaelnumero!

Elnumerosecretoes:7

Porfavorintroducetucorazonada.

4

Tucorazonadafue:4

$cargorun

Running`target/debug/adivinanzas`

Adivinaelnumero!

Elnumerosecretoes:83

Porfavorintroducetucorazonada.

5

Tucorazonadafue:5

Gradioso!Acontinuacion:comparemosnuestraadivinanzaconelnumerosecreto.

ComparandoadivinanzasAhoraquetenemosentradadelusuario,comparemoslaadivinanzaconnuestronumerosecreto.Heaquinuestrosiguientepaso,aunquetodavianofuncionacompletamente:

ElLenguajedeProgramacionRust

31ElJuegodelasAdivinanzas

Page 32: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

externcraterand;

usestd::io;

usestd::cmp::Ordering;

userand::Rng;

fnmain(){

println!("Adivinaelnumero!");

letnumero_secreto=rand::thread_rng().gen_range(1,101);

println!("Elnumerosecretoes:{}",numero_secreto);

println!("Porfavorintroducetucorazonada.");

letmutcorazonada=String::new();

io::stdin().read_line(&mutcorazonada)

.ok()

.expect("Falloalleerlinea");

println!("Tucorazonadafue:{}",corazonada);

matchcorazonada.cmp(&numero_secreto){

Ordering::Less=>println!("Muypequeño!"),

Ordering::Greater=>println!("Muygrande!"),

Ordering::Equal=>println!("Hazganado!"),

}

}

Algunaspiezasacá.Laprimeraesotrouse.Hemoshechodisponibleuntipollamadostd::cmp::Ordering.Despues,cinconuevaslineasalfondoquelousan:

matchcorazonada.cmp(&numero_secreto){

Ordering::Less=>println!("Muypequeño!"),

Ordering::Greater=>println!("Muygrande!"),

Ordering::Equal=>println!("Hazganado!"),

}

Elmetodocmp()puedeserllamadoancualquiercosaquepuedasercomparada,estetomaunareferenciaalacosaconlacualquierascomparar.RetornaeltipoOrderingquehicimosdisponibleanteriormente.HemosusadounasentenciamatchparadeterminarexactamentequetipodeOrderinges.Orderingesunenum,abreviacionpara‘enumeration’,lascualeslucendelasiguientemanera:

ElLenguajedeProgramacionRust

32ElJuegodelasAdivinanzas

Page 33: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

enumFoo{

Bar,

Baz,

}

Conestadefinición,cualquiercosadetipoFoopuedeserbienseaunFoo::BarounFoo::Baz.Usamosel::paraindicarelespaciodenombresparaunavarianteenumenparticular.

LaenumOrderingtienetresposiblesvariantes:Less,Equal,andGreater(menor,igualymayorrespectivamente).Lasentenciamatchtomaunvalordeuntipo,ytepermitecrearun‘brazo’paracadavalorposible.DebidoaquetenemostresposiblestiposdeOrdering,tenemostresbrazos:

matchguess.cmp(&secret_number){

Ordering::Less=>println!("Muypequeño!"),

Ordering::Greater=>println!("Muygrande!"),

Ordering::Equal=>println!("Hazganado!"),

}

SiesLess,imprimimosToosmall!,siesGreater,Toobig!,ysiesEqual,Hazganado!.matchesrealmenteutil,yesusadoconfercuenciaenRust.

Anteriormentemencionequetodavianofunciona.Pongamosloaprueba:

$cargobuild

Compilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

src/main.rs:28:21:28:35error:mismatchedtypes:

expected`&collections::string::String`,

found`&_`

(expectedstruct`collections::string::String`,

foundintegralvariable)[E0308]

src/main.rs:28matchcorazonada.cmp(&numero_secreto){

^~~~~~~~~~~~~~

error:abortingduetopreviouserror

Couldnotcompile`adivinanzas`.

Oops!Ungranerror.Loprincipalenelesquetenemos‘tiposincompatibles’(‘mismatchedtypes’).Rustposeeunfuerte,sistemadetiposestatico.Sinembargo,tambiéntieneinferenciadetipos.Cuandoescribimosletcorazonada=String::new(),RustfuecapazdeinferirquecorazonadadebiaserunString,yporellononoshizoescribireltipo.Connuestronumero_secreto,hayunnumerodetiposquepuedentenerunvalorentreunoycien:i32,unnumerodetreintaydosbits,u32,unnumerosinsignodetreintaydosbits,oi64unnumerodesesentaycuatrobitsuotros.Hastaahora,esonohaimportado,

ElLenguajedeProgramacionRust

33ElJuegodelasAdivinanzas

Page 34: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

debidoaqueRustpordefectousai32.Sinembargo,enestecaso,Rustnosabecomocompararcorazonadaconnumero_secreto.Ambosnecesitanserdelmismotipo.Alafinal,queremosconvertirelStringqueleimoscomoentradaenuntiporealdenumero,paraefectosdelacomparación.Podemoshaceresocontreslineasmas.Heaquinuestronuevoprograma:

externcraterand;

usestd::io;

usestd::cmp::Ordering;

userand::Rng;

fnmain(){

println!("Adivinaelnumero!");

letnumero_secreto=rand::thread_rng().gen_range(1,101);

println!("Elnumerosecretoes:{}",numero_secreto);

println!("Porfavorintroducetucorazonada.");

letmutcorazonada=String::new();

io::stdin().read_line(&mutcorazonada)

.ok()

.expect("Falloalleerlinea");

letcorazonada:u32=corazonada.trim().parse()

.ok()

.expect("Porfavorintroduceunnumero!");

println!("Tucorazonadafue:{}",corazonada);

matchcorazonada.cmp(&numero_secreto){

Ordering::Less=>println!("Muypequeño!"),

Ordering::Greater=>println!("Muygrande!"),

Ordering::Equal=>println!("Hazganado!"),

}

}

Lastresnuevaslineas:

letcorazonada:u32=corazonada.trim().parse()

.ok()

.expect("Porfavorintroduceunnumero!");

ElLenguajedeProgramacionRust

34ElJuegodelasAdivinanzas

Page 35: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Esperaunmomento,penséqueyateniamosunacorazonada?Latenemos,peroRustnospermitesobreescribir(‘shadow’)lacorazonadapreviaconunanueva.Estoesusadoconfrecuenciaenestamismasituación,endondecorazonadaesunString,peroqueremosconvertirloaunu32.Esteshadowingnospermitereusarelnombrecorazonadaenvezdeforzarnosaideardosnombresúnicoscomocorazonada_strycorazonada,uotros.

Estamosasociandocorazonadaaunaexpresiónquelucecomoalgoqueescribimosanteriormente:

guess.trim().parse()

Seguidoporunainvocaciónaok().expect().Aquícorazonadahacereferenciaalaviejaversión,laqueeraunStringqueconteníanuestraentradadeusuarioenella.Elmetodotrim()enlosStringseliminacualquierespacioenblancoalprincipioyalfinaldenuestrascadenasdecaracteres.Estoesimportante,debidoaquetuvimosquepresionarlatecla‘retorno’parasatisfaceraread_line().Estosignificaquesiescribimos5ypresionamos‘retorno’corazonadalucecomoasí:5\n.El\nrepresenta‘nuevalinea’(‘newline’),lateclaenter.trim()sedeshacedeesto,dejandonuestracadenadecaracteressoloconel5.Elmetodoparse()enlascadenascaracteresparseaunacadenadecaracteresenalgúntipodenumero.Debidoaquepuedeparsearunavariedaddenumeros,debemosdarleaRustunapistadeltipoexactodenumeroquedeseamos.Deahílaparteletcorazonada:u32.Losdospuntos(:)despuesdecorazonadaledicenaRustquevamosaanotareltipo.u32esunenterosinsignodetreintaydosbits.Rustposeeunavariedaddetiposnumerointegrados,peronosotroshemosescojidou32.Esunabuenaopciónpordefectoparaunnumeropositivopequeño.

Aligualqueread_line(),nuestrallamadaaparse()podriacausarunerror.QuetalsinuestracadenadecaracterescontieneA����?Nohabríaformadeconvertiresoenunnumero.Esporelloqueharemoslomismoquehicimosconread_line():usarlosmetodosok()yexpect()paraterminarabruptamentesihayalgunerror.

Probemosnuestroprograma!

$cargorun

Compilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

Running`target/adivinanzas`

Adivinaelnumero!

Elnumerosecretoes:58

Porfavorintroducetucorazonada.

76

Tucorazonadafue:76

Muygrande!

ElLenguajedeProgramacionRust

35ElJuegodelasAdivinanzas

Page 36: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Excelente!Puedesverqueinclusoheagregadoespaciosantesdemiintento,yaunasíelprogramadeterminoqueintente76.Ejecutaelprogramaunaspocasveces,yverificaqueadivinarelnumerofunciona,asicomointentarunnumeromuypequeno.

Ahoratenemoslamayoriadeljuegofuncionando,perosolopodemosintentaradivinarunavez.Tratemosdecambiaresoagregandociclos!

IteraciónLapalabraclaveloopnosproporcionauncicloinfinito.Agreguemosla:

Adivinaelnumero!Elnumerosecretoes:58Porfavorintroducetuadivinanza.76Tucorazonadafue:76Muygrande!

ElLenguajedeProgramacionRust

36ElJuegodelasAdivinanzas

Page 37: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

externcraterand;

usestd::io;

usestd::cmp::Ordering;

userand::Rng;

fnmain(){

println!("Adivinaelnumero!");

letnumero_secreto=rand::thread_rng().gen_range(1,101);

println!("Elnumerosecretoes:{}",numero_secreto);

loop{

println!("Porfavorintroducetucorazonada.");

letmutcorazonada=String::new();

io::stdin().read_line(&mutcorazonada)

.ok()

.expect("Falloalleerlinea");

letcorazonada:u32=corazonada.trim().parse()

.ok()

.expect("Porfavorintroduceunnumero!");

println!("Hazcorazonada:{}",corazonada);

matchcorazonada.cmp(&numero_secreto){

Ordering::Less=>println!("Muypequeño!"),

Ordering::Greater=>println!("Muygrande!"),

Ordering::Equal=>println!("Hazganado!"),

}

}

}

Pruebalo.Peroespera,noacabamosdeagregaruncicloinfinito?Sip.Recuerdasnuestradiscusiónacercadeparse()?Sidamosunarespuestanonumérica,retornaremos(return)yfinalizaremoslaejecución.Observa:

ElLenguajedeProgramacionRust

37ElJuegodelasAdivinanzas

Page 38: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$cargorun

Compilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

Running`target/adivinanzas`

Adivinaelnumero!

Elnumerosecretoes:59

Porfavorintroducetucorazonada.

45

Tucorazonadafue:45

Muypequeño!

Porfavorintroducetucorazonada.

60

Tucorazonadafue:60

Muygrande!

Porfavorintroducetucorazonada.

59

Tucorazonadafue:59

Hazganado!

Porfavorintroducetucorazonada.

quit

thread'<main>'panickedat'Pleasetypeanumber!'

Ja!quitenefectoterminalaejecución.Asicomocualquierotraentradaquenoseaunnumero.Bueno,estoessuboptimopordecirlomenos.Primerosalgamoscuandoganemos:

ElLenguajedeProgramacionRust

38ElJuegodelasAdivinanzas

Page 39: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

externcraterand;

usestd::io;

usestd::cmp::Ordering;

userand::Rng;

fnmain(){

println!("Adivinaelnumero!");

letnumero_secreto=rand::thread_rng().gen_range(1,101);

println!("Elnumerosecretoes:{}",numero_secreto);

loop{

println!("Porfavorintroducetucorazonada.");

letmutcorazonada=String::new();

io::stdin().read_line(&mutcorazonada)

.ok()

.expect("Falloalleerlinea");

letcorazonada:u32=corazonada.trim().parse()

.ok()

.expect("Porfavorintroduceunnumero!");

println!("Tucorazonadafue:{}",corazonada);

matchcorazonada.cmp(&numero_secreto){

Ordering::Less=>println!("Muypequeño!"),

Ordering::Greater=>println!("Muygrande!"),

Ordering::Equal=>{

println!("Hazganado!");

break;

}

}

}

}

Alagregarlalineabreakdespuesdel"Hazganado!",romperemoselciclocuandoganemos.Salirdelciclotambiénsignificasalirdelprograma,debidoaqueeslaultimacosaenmain().Solonosquedaunasolamejoraporhacer:cuandoalguienintroduzcaunvalornonumérico,noqueremosterminarlaejecución,queremossimplementeignorarlo.Podemoshacerlodelasiguientemanera:

ElLenguajedeProgramacionRust

39ElJuegodelasAdivinanzas

Page 40: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

externcraterand;

usestd::io;

usestd::cmp::Ordering;

userand::Rng;

fnmain(){

println!("Adivinaelnumero!");

letnumero_secreto=rand::thread_rng().gen_range(1,101);

println!("Elnumerosecretoes:{}",numero_secreto);

loop{

println!("Porfavorintroducetucorazonada.");

letmutcorazonada=String::new();

io::stdin().read_line(&mutcorazonada)

.ok()

.expect("Falloalleerlinea");

letcorazonada:u32=matchcorazonada.trim().parse(){

Ok(num)=>num,

Err(_)=>continue,

};

println!("Tucorazonadafue:{}",corazonada);

matchcorazonada.cmp(&numero_secreto){

Ordering::Less=>println!("Muypequeño!"),

Ordering::Greater=>println!("Muygrande!"),

Ordering::Equal=>{

println!("Hazganado!");

break;

}

}

}

}

Estassonlaslineasquehancambiado:

letcorazonada:u32=matchcorazonada.trim().parse(){

Ok(num)=>num,

Err(_)=>continue,

};

ElLenguajedeProgramacionRust

40ElJuegodelasAdivinanzas

Page 41: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Esasicomopasamosde‘terminarabruptamenteenunerror’a‘efectivamentemanejarelerror’,atravésdelcambiodeok().expect()aunasentenciamatch.ElResultretornadoporparse()esunenumjustocomoOrdering,peroenestecasocadavariantetienedataasociada:Okesexito,yErresunafalla.Cadaunocontienemasinformación:elenteroparseadoenelcasoexitoso,ountipodeerror.EnestecasohacemosmatchenOk(num),elcualasignaelvalorinternodelOkaelnombrenum,yseguidamenteretornaenelladoderecho.EnelcasodeErr,nonosimportaquetipodeerrores,esporelloqueusamos_enlugardeunnombre.Estoignoraelerrorycontinuenosmuevealasiguienteiteracióndelciclo(loop).

Ahoradeberiamosestarbien!Probemos:

$cargorun

Compilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

Running`target/adivinanzas`

Adivinaelnumero!

Elnumerosecretoes:61

Porfavorintroducetucorazonada.

10

Tucorazonadafue:10

Muypequeño!

Porfavorintroducetucorazonada.

99

Tucorazonadafue:99

Muypequeño!

Porfavorintroducetucorazonada.

foo

Porfavorintroducetucorazonada.

61

Tucorazonadafue:61

Hazganado!

Genial!Conunaultimamejora,finalizamoseljuegodelasadvinanzas.Teimaginascuales?Escorrecto,noqueremosimprimirelnumerosecreto.Erabuenoparalaspruebas,peroarruinanuestrojuego.Heaquinuestrocódigofuentefinal:

ElLenguajedeProgramacionRust

41ElJuegodelasAdivinanzas

Page 42: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

externcraterand;

usestd::io;

usestd::cmp::Ordering;

userand::Rng;

fnmain(){

println!("Adivinaelnumero!");

letnumero_secreto=rand::thread_rng().gen_range(1,101);

loop{

println!("Porfavorintroducetucorazonada.");

letmutcorazonada=String::new();

io::stdin().read_line(&mutcorazonada)

.ok()

.expect("Falloalleerlinea");

letcorazonada:u32=matchcorazonada.trim().parse(){

Ok(num)=>num,

Err(_)=>continue,

};

println!("Tucorazonadafue:{}",corazonada);

matchcorazonada.cmp(&numero_secreto){

Ordering::Less=>println!("Muypequeño!"),

Ordering::Greater=>println!("Muygrande!"),

Ordering::Equal=>{

println!("Hazganado!");

break;

}

}

}

}

Completado!Enestepunto,hasterminadosatisfactoriamenteeljuegodelasadivinanza!Felicitaciones!

Esteprimerproyectoteensenounmontón:let,match,metodos,funcionesasociadas,usarcratesexternos,ymas.Nuestrosiguienteproyectodemostraraaunmas.

ElLenguajedeProgramacionRust

42ElJuegodelasAdivinanzas

Page 43: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%LaCenadelosFilósofos

Paranuestrosegundoproyecto,echemosunvistazoaunproblemaclásicodeconcurrencia.Sellama‘Lacenadelosfilósofos’.FueoriginalmenteconcebidoporDijkstraen1965,peronosotrosusaremosunaversionligeramenteadaptadadeestepaperporTonyHoareen1985.

Entiemposancestrales,unfilántropoadineradopreparounauniversidadparaalojaracincofilósofoseminentes.Cadafilósofoteniaunahabitaciónenlacualpodíadesempeñarsuactividadprofesionaldelpensamiento:tambiénhabíauncomedorencomún,amobladoconunamesacircular,rodeadaporcincosillas,cadaunaidentificadaconelnombredelfilosofoquesesentabaenella.Losfilósofossesentabanensentidoanti-horarioalrededordelamesa.Alaizquierdadecadafilósofoyacíauntenedordorado,yenelcentrountazóndeespagueti,elcualeraconstantementerellenado.Seesperabaqueunfilósofoemplearalamayoríadesutiempopensando;perocuandosesintieranconhambre,sedirigieraaelcomedortomaraeltenedorqueestabaasuizquierdaylosumieranenelespagueti.Perotaleranaturalezaenredadadelespaguetiqueunsegundotenedorerarequeridoparallevarloalaboca.Elfilósofoporendeteniaquetambiéntomareltenedorasuderecha.Cuandoterminabandebíanbajarambostenedores,levantarsedelasillaycontinuarpensando.Porsupuesto,untenedorpuedeserusadoporunsolofilósofoalavez.Siotrofilósofolodesea,tienequeesperarhastaqueeltenedorestedisponiblenuevamente.

Esteproblemaclásicoexhibealgunoselementosdelaconcurrencia.Larazóndeelloesqueesunasoluciónefectivamentedifícildeimplementar:unaimplementaciónsimplepuedegenerarundeadlock.Porejemplo,consideremosunalgoritmosimplequepodríaresolveresteproblema:

1. Unfilósofotomaeltenedorasuizquierda.2. Despuéstomaeltenedorenasuderecha.3. Come.4. Bajalostenedores.

Ahora,imaginemosestasecuenciadeeventos:

1. Filosofo1comienzaelalgoritmo,tomandoeltenedorasuizquierda.2. Filosofo2comienzaelalgoritmo,tomandoeltenedorasuizquierda.3. Filosofo3comienzaelalgoritmo,tomandoeltenedorasuizquierda.4. Filosofo4comienzaelalgoritmo,tomandoeltenedorasuizquierda.5. Filosofo5comienzaelalgoritmo,tomandoeltenedorasuizquierda.6. ...?Todoslostenedoreshansidotomados,peronadiepuedecomer!

ElLenguajedeProgramacionRust

43LaCenadelosFilósofos

Page 44: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Existendiferentesformasderesolveresteproblema.Teguiaremosatravésdelasolucióndeestetutorial.Porahora,comencemosmodelandoelproblema.Empecemosconlosfilósofos:

structFilosofo{

nombre:String,

}

implFilosofo{

fnnew(nombre:&str)->Filosofo{

Filosofo{

nombre:nombre.to_string(),

}

}

}

fnmain(){

letf1=Filosofo::new("JudithButler");

letf2=Filosofo::new("GillesDeleuze");

letf3=Filosofo::new("KarlMarx");

letf4=Filosofo::new("EmmaGoldman");

letf5=Filosofo::new("MichelFoucault");

}

Acá,creamosunaestructura(struct)pararepresentarunfilósofo.Porahoraelnombreestodoloquenecesitamos.ElegimoseltipoStringparaelnombre,envezde&str.Generalmentehablando,trabajarcontipoqueesdueño(poseepertenencia)desudataesmasfácilquetrabajarconunoqueusereferencias.

Continuemos:

#structFilosofo{

#nombre:String,

#}

implFilosofo{

fnnew(nombre:&str)->Filosofo{

Filosofo{

nombre:nombre.to_string(),

}

}

}

EstebloqueimplnospermitedefinircosasenestructurasFilosofo.Enestecasoestamosdefiniendouna‘funciónasociada’llamadanew.Laprimeralinealuceasí:

ElLenguajedeProgramacionRust

44LaCenadelosFilósofos

Page 45: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#structFilosofo{

#nombre:String,

#}

#implFilosofo{

fnnew(nombre:&str)->Filosofo{

#Filosofo{

#nombre:nombre.to_string(),

#}

#}

#}

Recibimosunargumento,nombre,detipo&str.Unareferenciaaotracadenadecaracteres.EstaretornaunainstanciadenuestraestructuraFilosofo.

#structFilosofo{

#nombre:String,

#}

#implFilosofo{

#fnnew(nombre:&str)->Filosofo{

Filosofo{

nombre:nombre.to_string(),

}

#}

#}

LoanteriorcreaunnuevoFilosofo,yasignanuestroargumentonombreaelcamponombre.Noaelargumentoensimismo,debidoaquellamamos.to_string()enel.Locualcreaunacopiadelacadenaalaqueapuntanuestro&str,ynosdaunnuevoString,queesdeltipodelcamponombredeFilosofo.

PorquenoaceptarunStringdirectamente?Esmasfácildellamar.SirecibiéramosunStringperoquiennosllamatuvieseun&strellosseveríanenlaobligacióndellamar.to_string()desulado.Ladesventajadeestaflexibilidadesquesiemprehacemosunacopia.Paraestepequeñoprograma,estonoesparticularmenteimportante,yquesabemosqueestaremosusandocadenascortasdecualquiermodo.

Unaultimacosasquehabrásnotado:solodefinimosunFilosofo,ynoparecemoshacernadaconel.Rustesunlenguaje‘basadoenexpresiones’,loquesignificaquecasicualquiercosaenRustesunaexpresiónqueretornaunvalor.Estoesciertoparalasfuncionestambién,laultimaexpresiónesretornadaautomáticamente.DebidoaquecreamosunnuevoFilosofocomolaultimaexpresióndeestafunción,terminamosretornándolo.

ElLenguajedeProgramacionRust

45LaCenadelosFilósofos

Page 46: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Elnombrenew(),noesnadaespecialparaRust,peroesunaconvenciónparafuncionesquecreannuevasinstanciasdeestructuras.Antesquehablemosdelporque,echamosunvistazoamain()otravez:

#structFilosofo{

#nombre:String,

#}

#

#implFilosofo{

#fnnew(nombre:&str)->Filosofo{

#Filosofo{

#nombre:nombre.to_string(),

#}

#}

#}

#

fnmain(){

letf1=Filosofo::new("JudithButler");

letf2=Filosofo::new("GillesDeleuze");

letf3=Filosofo::new("KarlMarx");

letf4=Filosofo::new("EmmaGoldman");

letf5=Filosofo::new("MichelFoucault");

}

Acá,creamoscincovariablesconcinconuevosfilósofos.Estossonmiscincofavoritos,peropuedessubstituirlosconquienesprefieras.Denohaberdefinidolafunciónnew(),main()luciríaasí:

#structFilosofo{

#nombre:String,

#}

fnmain(){

letf1=Filosofo{nombre:"JudithButler".to_string()};

letf2=Filosofo{nombre:"GillesDeleuze".to_string()};

letf3=Filosofo{nombre:"KarlMarx".to_string()};

letf4=Filosofo{nombre:"EmmaGoldman".to_string()};

letf5=Filosofo{nombre:"MichelFoucault".to_string()};

}

Unpocomasruidoso.Usarnewtienetambiénposeeotrasventajas,peroinclusoenestesimplecasoterminaporserdemejorutilidad.

Ahoraquetenemoslobásicoensulugar,hayunnumerodemanerasenlascualespodemosatacarelproblemamasamplio.Amimegustacomenzarporelfinal:creemosunaformaparaquecadafilosofopuedafinalizardecomer.Comounpasopequeño,hagamosunmétodo,yluegoiteremosatravésdetodoslosfilósofosllamándolo:

ElLenguajedeProgramacionRust

46LaCenadelosFilósofos

Page 47: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

structFilosofo{

nombre:String,

}

implFilosofo{

fnnew(nombre:&str)->Filosofo{

Filosofo{

nombre:nombre.to_string(),

}

}

fncomer(&self){

println!("{}hafinalizadodecomer.",self.nombre);

}

}

fnmain(){

letfilosofos=vec![

Filosofo::new("JudithButler"),

Filosofo::new("GillesDeleuze"),

Filosofo::new("KarlMarx"),

Filosofo::new("EmmaGoldman"),

Filosofo::new("MichelFoucault"),

];

forfin&filosofos{

f.comer();

}

}

Primeroveamosamain().Enlugardetenercincovariablesindividualesparanuestrosfilósofos,creamosunVec<T>.Vec<T>esllamadotambiénun‘vector’,yesunarreglocapazdecrecer.Despuésusamosunciclo[for][for]paraiteraratravésdelvector,obteniendounreferenciaacadafilosofoalavez.

Enelcuerpodelbucle,llamamosf.comer();,queestadefinidocomo:

fncomer(&self){

println!("{}hafinalizadodecomer.",self.nombre);

}

EnRust,losmétodosrecibenunparámetroexplícitoself.Esporelloquecomer()esunmétodoynewesunafunciónasociada:new()notieneself.Paranuestraprimeraversiondecomer(),soloimprimimoselnombredelfilósofo,ymencionamosquehafinalizadodecomer.Ejecutaresteprogramadebergenerarlasiguientesalida:

ElLenguajedeProgramacionRust

47LaCenadelosFilósofos

Page 48: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

JudithButlerhafinalizadodecomer.

GillesDeleuzehafinalizadodecomer.

KarlMarxhafinalizadodecomer.

EmmaGoldmanhafinalizadodecomer.

MichelFoucaulthafinalizadodecomer.

Muyfácil,todoshanterminadodecomer!Peronohemosimplementadoelproblemarealtodavía,asíqueaunnoterminamos!

Acontinuación,nosoloqueremossolofinalicendecomer,sinoqueefectivamentecoman.Heaquílasiguienteversión:

usestd::thread;

structFilosofo{

nombre:String,

}

implFilosofo{

fnnew(nombre:&str)->Filosofo{

Filosofo{

nombre:nombre.to_string(),

}

}

fncomer(&self){

println!("{}estacomiendo.",self.nombre);

thread::sleep_ms(1000);

println!("{}hafinalizadodecomer.",self.nombre);

}

}

fnmain(){

letfilosofos=vec![

Filosofo::new("JudithButler"),

Filosofo::new("GillesDeleuze"),

Filosofo::new("KarlMarx"),

Filosofo::new("EmmaGoldman"),

Filosofo::new("MichelFoucault"),

];

forfin&filosofos{

f.comer();

}

}

Solounospocoscambios.Analicémoslosparteporparte.

ElLenguajedeProgramacionRust

48LaCenadelosFilósofos

Page 49: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::thread;

usehacedisponiblesnombresennuestroámbito(scope).Comenzaremosausarelmodulothreaddelabibliotecaestándar,yesporelloquenecesitamoshaceruseenel.

fncomer(&self){

println!("{}estacomiendo.",self.nombre);

thread::sleep_ms(1000);

println!("{}hafinalizadodecomer.",self.nombre);

}

Ahoraestamosimprimiendodosmensajes,conunsleep_ms()enelmedio.Locualsimularaeltiempoquetardaunfilosofoencomer.

Siejecutasesteprograma,deberiasvercomeracadafilosofoalavez:

JudithButlerestacomiendo.

JudithButlerhafinalizadodecomer.

GillesDeleuzeestacomiendo.

GillesDeleuzehafinalizadodecomer.

KarlMarxestacomiendo.

KarlMarxhafinalizadodecomer.

EmmaGoldmanestacomiendo.

EmmaGoldmanhafinalizadodecomer.

MichelFoucaultestacomiendo.

MichelFoucaulthafinalizadodecomer.

Excelente!Estamosavanzando.Solohayundetalle:noestamosoperandodemaneraconcurrente,locualespartecentraldenuestroproblema!

Parahaceranuestrosfilósofoscomerdemaneraconcurrente,necesitamoshacerunpequeñocambio.

Heaquilasiguienteiteración:

ElLenguajedeProgramacionRust

49LaCenadelosFilósofos

Page 50: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::thread;

structFilosofo{

nombre:String,

}

implFilosofo{

fnnew(nombre:&str)->Filosofo{

Filosofo{

nombre:nombre.to_string(),

}

}

fncomer(&self){

println!("{}estacomiendo.",self.nombre);

thread::sleep_ms(1000);

println!("{}hafinalizadodecomer.",self.nombre);

}

}

fnmain(){

letfilosofos=vec![

Filosofo::new("JudithButler"),

Filosofo::new("GillesDeleuze"),

Filosofo::new("KarlMarx"),

Filosofo::new("EmmaGoldman"),

Filosofo::new("MichelFoucault"),

];

lethandles:Vec<_>=filosofos.into_iter().map(|f|{

thread::spawn(move||{

f.comer();

})

}).collect();

forhinhandles{

h.join().unwrap();

}

}

Todoloquehemoshechoescambiarelcicloenmain(),yagregadounsegundo!Esteeselprimercambio:

lethandles:Vec<_>=filosofos.into_iter().map(|f|{

thread::spawn(move||{

f.comer();

})

}).collect();

ElLenguajedeProgramacionRust

50LaCenadelosFilósofos

Page 51: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Aunasísonsolocincolineas,soncincodensaslineas.Analicemosporpartes.

lethandles:Vec<_>=

Introducimosunanuevavariable,llamadahandles.Lehemosdadoestenombreporquecrearemosalgunosnuevoshilos,queresultaranenalgunoshandles(agarradores,manillas)aesosdichoshilosloscualesnospermitiráncontrolarsuoperación.Necesitamosanotareltipoexplícitamente,debidoaalgoqueharemosreferenciamasadelante.El_esunmarcadordeposiciónparauntipo.Estamosdiciendo“handlesesunvectordealgo,perotu,Rust,puedesdeterminarqueesesealgo.”

filosofos.into_iter().map(|f|{

Tomamosnuestralistadefilósofosyllamamosinto_iter()enella.Estocreauniteradorqueseadueña(tomapertenencia)decadafilosofo.Necesitamoshacerestoparapoderpasarlosfilósofosanuestroshilos.Luegotomamoseseiteradoryllamamosmapenel,métodoquetomaunclosurecomoargumentoyllamadichoclosureencadaunodeloselementosalavez.

thread::spawn(move||{

f.comer();

})

Esaquídondelaconcurrenciaocurre.Lafunciónthread::spawntomaunclosurecomoargumentoyejecutaeseclosureenunnuevohilo.Elclosurenecesitaunaanotaciónextra,move,paraindicarqueelclosurevaaadueñarsedelosvaloresqueestacapturando.Principalmente,lavariablefdelafunciónmap.

Dentrodelhilo,todoloquehacemosesllamaracomer();enf.

}).collect();

Finalmente,tomamoselresultadodetodosesasllamadasamapyloscoleccionamos.collect()losconvertiráenunacoleccióndealgunatipo,queeselporqueanotamoseltipoderetorno:queremosunVec<T>.Loselementossonlosvaloresretornadosdelasllamadasathread::spawn,quesonhandlesaesoshilos.Whew!

forhinhandles{

h.join().unwrap();

}

ElLenguajedeProgramacionRust

51LaCenadelosFilósofos

Page 52: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Alfinaldemain(),iteramosatravésdeloshandlesllamandojoin()enellos,locualbloquealaejecuciónhastaqueelhilohayacompletadosuejecución.Estoaseguraqueelhilocompletesuejecuciónantesqueelprogramatermine.

Siejecutasesteprograma,verasquelosfilósofoscomensinorden!Tenemosmulti-hilos!

GillesDeleuzeestacomiendo.

GillesDeleuzehafinalizadodecomer.

EmmaGoldmanestacomiendo.

EmmaGoldmanhafinalizadodecomer.

MichelFoucaultestacomiendo.

JudithButlerestacomiendo.

JudithButlerhafinalizadodecomer.

KarlMarxestacomiendo.

KarlMarxhafinalizadodecomer.

MichelFoucaulthafinalizadodecomer.

Peroqueacercadelostenedoresnoloshemosmodeladodeltodotodavía.

Parahacerlo,creemosunnuevostruct:

usestd::sync::Mutex;

structMesa{

tenedores:Vec<Mutex<()>>,

}

EstaMesacontieneunvectordeMutexes.Unmutexesunaformadecontrolarconcurrencia,solounhilopuedeaccederelcontenidoalavez.Estaeslaexactamentelapropiedadquenecesitamosparanuestrostenedores.Usamosunaduplavacía,(),dentrodelmutex,debidoaquenovamosausarelvalor,solonosaferraremosael.

ModifiquemoselprogramaparahacerusodeMesa:

usestd::thread;

usestd::sync::{Mutex,Arc};

structFilosofo{

nombre:String,

izquierda:usize,

derecha:usize,

}

implFilosofo{

fnnew(nombre:&str,izquierda:usize,derecha:usize)->Filosofo{

Filosofo{

nombre:nombre.to_string(),

izquierda:izquierda,

ElLenguajedeProgramacionRust

52LaCenadelosFilósofos

Page 53: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

derecha:derecha,

}

}

fncomer(&self,mesa:&Mesa){

let_izquierda=mesa.tenedores[self.izquierda].lock().unwrap();

let_derecha=mesa.tenedores[self.derecha].lock().unwrap();

println!("{}estacomiendo.",self.nombre);

thread::sleep_ms(1000);

println!("{}hafinalizadodecomer.",self.nombre);

}

}

structMesa{

tenedores:Vec<Mutex<()>>,

}

fnmain(){

letmesa=Arc::new(Mesa{tenedores:vec![

Mutex::new(()),

Mutex::new(()),

Mutex::new(()),

Mutex::new(()),

Mutex::new(()),

]});

letfilosofos=vec![

Filosofo::new("JudithButler",0,1),

Filosofo::new("GillesDeleuze",1,2),

Filosofo::new("KarlMarx",2,3),

Filosofo::new("EmmaGoldman",3,4),

Filosofo::new("MichelFoucault",0,4),

];

lethandles:Vec<_>=filosofos.into_iter().map(|f|{

letmesa=mesa.clone();

thread::spawn(move||{

f.comer(&mesa);

})

}).collect();

forhinhandles{

h.join().unwrap();

}

}

Muchoscambios!Sinembargo,conestaiteración,hemosobtenidounprogramafuncional.Veamoslosdetalles:

ElLenguajedeProgramacionRust

53LaCenadelosFilósofos

Page 54: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::sync::{Mutex,Arc};

Usaremosotraestructuradelpaquetestd::sync:Arc<T>.

Hablaremosmasacercadeellacuandolausemos.

structFilosofo{

nombre:String,

izquierda:usize,

derecha:usize,

}

VamosanecesitaragregardoscamposmasanuestraestructuraFilosofo.Cadafilosofotendrádostenedores:eldelaizquierda,yeldeladerecha.Usaremoseltipousizeparaindicarlos,debidoaqueesteeseltipoconelcualseindexanlosvectores.EstosdosvaloresseránindicesenlostenedoresquenuestraMesaposee.

fnnew(nombre:&str,izquierda:usize,derecha:usize)->Filosofo{

Filosofo{

nombre:nombre.to_string(),

izquierda:izquierda,

derecha:derecha,

}

}

Ahoranecesitamosconstruiresosvaloresizquierdayderecha,demaneraquepodamosagregarlosanew().

fncomer(&self,mesa:&Mesa){

let_izquierda=mesa.tenedores[self.izquierda].lock().unwrap();

let_derecha=mesa.tenedores[self.derecha].lock().unwrap();

println!("{}estacomiendo.",self.nombre);

thread::sleep_ms(1000);

println!("{}hafinalizadodecomer.",self.nombre);

}

Tenemosdosnuevaslineas,tambiénhemosagregadounargumento,mesa.AccedemosalalistadetenedoresdelaMesa,ydespuésusamosself.izquierdayself.derechaparaaccederaltenedorenunindiceenparticular.EsonosdaaccesoalMutexeneseindice,endondellamamoslock().Sielmutexestasiendoaccedidoactualmenteporalguienmas,nosbloquearemoshastaqueestedisponible.

ElLenguajedeProgramacionRust

54LaCenadelosFilósofos

Page 55: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Lallamadaalock()puedefallar,ysilohace,queremosterminarabruptamente.Enestecasoelerrorquepuedeocurriresqueelmutexeste‘envenenado’(‘poisoned’),queesloqueocurrecuandoelhilohacepánicomientraselmantieneelbloqueo.Debidoaqueestonodeberíaocurrir,simplementeusamosunwrap().

Otracosaextrañaacercadeestalineas:hemosnombradolosresultados_izquierdaand_derecha.Quehayconesesub-guion?Bueno,enrealidadnoplaneamosusarelvalordentrodelbloqueo.Soloqueremosadquirirlo.Aconsecuencia,Rustnosadvertiráquenuncausamoselvalor.Atravésdelusodelsub-guionledecimosaRustqueesloquequisimos,deesamaneranogeneraralaadvertencia.

Queacercadesoltarelbloqueo?,Bueno,estoocurrirácuando_izquierday_derechasalgandeámbito,automáticamente.

letmesa=Arc::new(Mesa{tenedores:vec![

Mutex::new(()),

Mutex::new(()),

Mutex::new(()),

Mutex::new(()),

Mutex::new(()),

]});

Acontinuación,enmain(),creamosunanuevaMesaylaenvolvemosenunArc<T>.‘arc’provienede‘atomicreferencecount’(cuentadereferenciasatómica),necesitamoscompartirnuestraMesaentremultipleshilos.Amediaquelacompartimos,lacuentadereferenciassubirá,ycuandocadahilotermine,irabajando.

letfilosofos=vec![

Filosofo::new("JudithButler",0,1),

Filosofo::new("GillesDeleuze",1,2),

Filosofo::new("KarlMarx",2,3),

Filosofo::new("EmmaGoldman",3,4),

Filosofo::new("MichelFoucault",0,4),

];

NecesitamospasarnuestrosvaloresizquierdaandderechaalosconstructoresdenuestrosFilosofos.Perohayundetallemasaquí,yesmuyimportante.Siobservasalpatrón,esconsistentehastaelfinal,MonsieurFoucaultdebetener4,0comoargumentos,peroenvezdeestotiene0,4.Estoesloqueprevienedeadlocks,enefecto:unodelosfilósofoseszurdo!Esaesunaformaderesolverelproblema,yenmiopinion,eslamassimple.

ElLenguajedeProgramacionRust

55LaCenadelosFilósofos

Page 56: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

lethandles:Vec<_>=filosofos.into_iter().map(|f|{

letmesa=mesa.clone();

thread::spawn(move||{

f.comer(&mesa);

})

}).collect();

Finalmente,dentrodenuestrociclomap()/collect(),llamamosmesa.clone().Elmétodoclone()enArc<T>esloqueincrementalacuentadereferencias,ycuandosaledeámbito,ladecrementa.Notarasquepodemosintroducirunanuevavariablemesa,yestasobreescribirá(shadow)laanterior.Estoesfrecuentementeusadodemanerataldenotenerqueinventardosnombresúnicos.

Contodoesto,nuestroprogramafunciona!Solodosfilosofopuedencomerenunmomentodadoyenconsecuenciatendrássalidaseveraasí:

GillesDeleuzeestacomiendo.

EmmaGoldmanestacomiendo.

EmmaGoldmanhafinalizadodecomer.

GillesDeleuzehafinalizadodecomer.

JudithButlerestacomiendo.

KarlMarxestacomiendo.

JudithButlerhafinalizadodecomer.

MichelFoucaultestacomiendo.

KarlMarxhafinalizadodecomer.

MichelFoucaulthafinalizadodecomer.

Felicitaciones!HazimplementadounproblemaclásicodeconcurrenciaenRust.

ElLenguajedeProgramacionRust

56LaCenadelosFilósofos

Page 57: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%RustDentrodeOtrosLenguajes

Paranuestrotercerproyecto,elegiremosalgoquedemuestraunadelasmayoresfortalezasdeRust:laausenciadeunentornodeejecución.

Amedidaquelasorganizacionescrecen,estasdemaneraprogresiva,hacenusodeunamultituddelenguajesdeprogramación.Diferenteslenguajesdeprogramaciónposeendiferentesfortalezasydebilidades,yunaarquitecturapoliglotapermiteusarunlenguajeenparticulardondesusfortalezashagansentidoyotrolenguajeseadébil.

Unareamuycomúnendondemuchoslenguajesdeprogramaciónsondébileseselperformanceentiempodeejecución.Frecuentemente,usarunlenguajequeeslento,peroofrecemayorproductividadparaelprogramador,esunequilibrioquevalelapena.Paraayudaramitigaresto,dichoslenguajesproveenunamaneradeescribirunapartedetusistemaenCyluegollamaresecódigocomosihubiesesidoescritoenunlenguajedemasaltonivel.Estafacilidadesdenominada‘interfazdefuncionesforáneas’(‘foreignfunctioninterface’),comúnmenteabreviandoa‘FFI’.

RustposeesoporteparaFFIenambasdirecciones:puedellamarcódigoenCdemanerafácil,perocrucialmentepuedeserllamadotanfácilmentecomoC.Combinadoconlaausenciadeunrecolectordebasuraybajosrequerimientosentiempodeejecución,RustesuncandidatoparaserembebidodentrodeotroslenguajescuandonecesitesesosooKmhextra.

ExisteuncapitulocompletodedicadoaFFIysusdetallesenotrapartedellibro,peroenestecapitulo,examinaremoselusoparticulardeFFIconejemplosenRuby,Python,yJavaScript.

ElproblemaExistenmuchosproblemasquepodríamoshaberescogido,peroelegiremosunejemploenelcualRusttieneunaventajaclaraporencimadeotroslenguajes:computaciónnuméricaehilos.

Muchoslenguajes,enhonoralaconsistencia,colocannúmerosenelmontículo,envezdeenlapila.Especialmenteenlenguajesenfocadosenprogramaciónorientadaaobjetosyelusodeunrecolectordebasura,laasignacióndememoriadesdeelmontículoeselcomportamientopordefecto.Algunasvecesoptimizacionespuedencolocarciertosnúmerosenlapila,peroenvezdeconfiarenunoptimizadorpararealizarestetrabajo,podríamosquererasegurarnosquesiempreestemosusandonumeroprimitivosenvezdealguntipodeobjetos.

ElLenguajedeProgramacionRust

57RustdentrodeotrosLenguajes

Page 58: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Segundo,muchoslenguajesposeenun‘bloqueoglobaldelinterprete’(‘globalinterpreterlock’)(GIL),quelimitalaconcurrenciaenmuchassituaciones.Estoeshechoenelnombredelaseguridadlocualesunefectopositivo,perolimitalacantidaddetrabajoquepuedeserllevadoacabodemaneraconcurrente,locualesungrannegativo.

Paraenfatizarestos2aspectos,crearemosunpequeñoproyectoqueusaestosdosaspectosengranmedida.DebidoaqueelfocodelejemploesembeberRustenotroslenguajes,envezdeelproblemaensimismo,usaremosunejemplodejuguete:

Iniciadiezhilos.Dentrodecadahilo,cuentadesdeunohastacincomillones.Despuésquetodosloshiloshayanfinalizado,imprime"completado!".

Heescogidocincomillonesbasadoenmicomputadorenparticular.HeaquíunejemplodeestecódigoenRuby:

threads=[]

10.timesdo

threads<<Thread.newdo

count=0

5_000_000.timesdo

count+=1

end

end

end

threads.each{|t|t.join}

puts"completado!"

Intentaejecutaresteejemplo,yescogeunnumeroquecorraporunossegundos.Dependiendoenelhardwaredetucomputador,tendrásqueincrementarodecrementarelnumero.

Enmisistema,ejecutaresteprogramatoma2.156.Siusoalgunatipodeherramientademonitoreodeprocesos,comotop,puedoverquesolousaunnúcleoenmimaquina.ElGILpresentehaciendosutrabajo.

Sibienesciertoqueesteenunprogramasintético,unopodríaimaginarmuchosproblemassimilaresaesteenelmundoreal.Paranuestrospropósitos,levantarunospocoshilosyocuparlosrepresentaunaespeciedecomputaciónparalelaycostosa.

UnabibliotecaRust

ElLenguajedeProgramacionRust

58RustdentrodeotrosLenguajes

Page 59: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

EscribamosesteproblemaenRust.Primero,creemosunproyectonuevoconCargo:

$cargonewembeber

$cdembeber

EsteprogramaesfácildeescribirenRust:

usestd::thread;

fnprocesar(){

lethandles:Vec<_>=(0..10).map(|_|{

thread::spawn(||{

letmut_x=0;

for_in(0..5_000_000){

_x+=1

}

})

}).collect();

forhinhandles{

h.join().ok().expect("Nosepudounirunhilo!");

}

}

Algodeestodebelucirfamiliaraejemplosanteriores.Iniciamosdiezhilos,colectandolosenunvectorhandles.Dentrodecadahilo,iteramoscincomillonesdeveces,agregandounoa_xencadaiteración.Porqueelsub-guion?Bueno,siloremovemosyluegocompilamos:

$cargobuild

Compilingembeberv0.1.0(file:///Users/goyox86/Code/rust/embeber)

src/lib.rs:3:1:16:2warning:functionisneverused:`procesar`,#[warn(dead_code)]onbydefault

src/lib.rs:3fnprocesar(){

src/lib.rs:4lethandles:Vec<_>=(0..10).map(|_|{

src/lib.rs:5thread::spawn(||{

src/lib.rs:6letmutx=0;

src/lib.rs:7for_in(0..5_000_000){

src/lib.rs:8x+=1

...

src/lib.rs:6:17:6:22warning:variable`x`isassignedto,butneverused,#[warn(unused_variables)]onbydefault

src/lib.rs:6letmutx=0;

^~~~~

Laprimeraadvertenciaesdebidoesaconsecuenciadeestarconstruyendounabiblioteca.Situviéramosunapruebaparaestafunción,laadvertenciadesaparecería.Peroporahoranuncaesllamada.

ElLenguajedeProgramacionRust

59RustdentrodeotrosLenguajes

Page 60: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Lasegundaestarelacionadaaxversus_x.Comoproductodequeefectivamentenohacemosnadaconxobtenemosunaadvertencia.Eso,ennuestrocaso,estaperfectamentebien,puestoquequeremosdesperdiciarciclosdeCPU.Usandounsub-guióndeprefijoeliminamoslaadvertencia.

Finalmente,hacemosjoinencadaunodeloshilos.

Hastaelmomento,sinembargo,esunabibliotecaRust,ynoexponenadaquepuedaserllamadodesdeC.Siquisiéramosconectarlaconotrolenguaje,ensuestadoactual,nofuncionaria.Solonecesitamoshacerunospequeñoscambiosparaarreglarlo.Loprimeroesmodificarelprincipiodenuestrocódigo:

#[no_mangle]

pubexternfnprocesar(){

Debemosagregarunnuevoatributo,no_mangle.CuandocreamosunabibliotecaRust,estecambiaelnombredelafunciónenlasalidacompilada.Lasrazonesdeestoescapandelalcancedeestetutorial,peroparaqueotroslenguajespuedansabercomollamaralafunción,debemosevitarqueelcompiladorcambieelnombreenlasalidacompilada.Esteatributodesactivaesecomportamiento.

Elotrocambioeselpubextern.Elpubsignificaqueestafunciónpuedeserllamadadesdeafueradeestemodulo,yelexterndicequeestapuedeserllamadadesdeC.Esoestodo!Nomuchoscambios.

LasegundacosaquenecesitamoshacerescambiarunaconfiguraciónennuestroCargo.toml.Agregaestoalfinal:

[lib]

name="embeber"

crate-type=["dylib"]

EstaslineasleinformanaRustquequeremoscompilarnuestrabibliotecaenunabibliotecadinámicaestándar.Rustcompilaun‘rlib’,unformatoespecificodeRust.

Ahoraconstruyamoselproyecto:

$cargobuild--release

Compilingembeberv0.1.0(file:///Users/goyox86/Code/rust/embeber)

Hemoselegidocargobuild--release,locualconstruyeelproyectoconoptimizaciones.Queremosquesealomasrápidoposible!Puedesencontrarlasalidadelabibliotecaentarget/release:

ElLenguajedeProgramacionRust

60RustdentrodeotrosLenguajes

Page 61: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$lstarget/release/

builddepsexampleslibembeber.dylibnative

Esalibembeber.dylibesnuestrabibliotecade‘objetoscompartidos’.PodemosusarestabibliotecacomocualquierbibliotecadeobjetoscompartidoescritaenC!Comonota,estapodríaserlibembeber.soolibembeber.dll,dependiendolaplataforma.

AhoraquetenemosnuestrabibliotecaRust,usémosladesdeRuby.

RubyCreaunarchivoembeber.rbdentrodenuestroproyecto,ycolocaestodentro:

require'ffi'

moduleHola

extendFFI::Library

ffi_lib'target/release/libembeber.dylib'

attach_function:procesar,[],:void

end

Hola.procesar

puts'completado!'

Antesdequepodamosejecutarlo,necesitamosinstalarlagemaffi:

$geminstallffi#estopuedenecesitarsudo

Fetching:ffi-1.9.8.gem(100%)

Buildingnativeextensions.Thiscouldtakeawhile...

Successfullyinstalledffi-1.9.8

Parsingdocumentationforffi-1.9.8

Installingridocumentationforffi-1.9.8

Doneinstallingdocumentationforffiafter0seconds

1geminstalled

Finalmente,intentemosejecutarlo:

$rubyembeber.rb

completado!

$

ElLenguajedeProgramacionRust

61RustdentrodeotrosLenguajes

Page 62: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Whoa,esofuerápido!Enmisistema,tomo0.086segundos,adiferenciadelosdossegundosquelaversionenRubypuro.AnalicemosestecódigoRuby:

require'ffi'

Primeronecesitamosrequerirlagemaffi.NospermiteinteractuarconunabibliotecaRustcomounabibliotecaenC.

moduleHola

extendFFI::Library

ffi_lib'target/release/libembeber.dylib'

ElmoduloHolaesusadoparaadjuntarlasfuncionesnativasdelabibliotecacompartida.Dentro,extendemoselmoduloFFI::Libraryyluegollamamoselmétodoffi_libparacargarnuestrabibliotecadeobjetoscompartidos.Simplementepasamoslarutaenlacualnuestrabibliotecaestaalmacenada,lacual,comovimosanteriormente,estarget/release/libembeber.dylib.

attach_function:procesar,[],:void

Elmétodoattach_functionesproporcionadoporlagemaFFI.Esloqueconectanuestrafunciónprocesar()enRustaunmétodoenRubyconelmismonombre.Debidoaqueprocesar()norecibeargumentos,elsegundoparámetroesunarreglovacío,yyaquenoretornanada,pasamos:voidcomoargumentofinal.

Hola.procesar

EstaeslallamadaaRust.Lacombinacióndenuestromoduloylallamadaaattach_functionhanconfiguradotodo.SevecomounmétodoRubyperoesenrealidadcódigoRust!

puts'completado!'

Finalmente,ycomorequerimientodenuestroproyecto,imprimimoscompletado!.

Esoestodo!Comohemosvisto,hacerunpuenteentrelosdoslenguajesesrealmentefácil,ynoscompramuchoperformance.

Acontinuación,probemosPython!

ElLenguajedeProgramacionRust

62RustdentrodeotrosLenguajes

Page 63: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

PythonCreaunarchivoembeber.pyenestedirectorio,ycolocaestoenel:

fromctypesimportcdll

lib=cdll.LoadLibrary("target/release/libembeber.dylib")

lib.procesar()

print("completado!")

Aunmasfácil!Usamoscdlldelmoduloctypes.UnallamadarápidaaLoadLibrarydespués,yluegopodemosllamarprocesar().

Enmisistema,toma0.017segundos.Rápidillo!

Node.jsNodenoesunlenguaje,peroesactualmentelaimplementacióndeJavascriptdominantedelladodelservidor.

ParahacerFFIconNode,primeronecesitamosinstalarlabiblioteca:

$npminstallffi

Despuésdequeesteinstalada,podemosusarla:

varffi=require('ffi');

varlib=ffi.Library('target/release/libembeber',{

'procesar':['void',[]]

});

lib.procesar();

console.log("completado!");

LucemasparecidoalejemploRubyquealdePython.Usamoselmoduloffiparaobteneraccesoaffi.Library(),lacualnospermitecargarnuestrabibliotecadeobjetoscompartidos.Necesitamosanotareltipoderetornoylostiposdelosargumentosdela

ElLenguajedeProgramacionRust

63RustdentrodeotrosLenguajes

Page 64: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

función,quesonvoidparaelretornoyunarreglovacíopararepresentarningúnargumento.Deallísimplementellamamosalafunciónprocesar()eimprimimoselresultado.

Enmysistema,esteejemplotomaunosrápidos0.092segundos.

ConclusionComopuedesver,lasbasesdehacerFFIsonmuyfáciles.Porsupuestohaymuchomasquepodríamoshaceraquí.EchaunvistazoalcapituloFFIparamasdetalles.

ElLenguajedeProgramacionRust

64RustdentrodeotrosLenguajes

Page 65: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%RustEfectivo

Entonces,hazaprendidocomoescribiralgodecódigoRust.PerohayunadiferenciaentreescribircualquiercódigoRustyescribirbuencódigoRust.

EstasecciónconsistedetutorialesrelativamenteindependientesquetemuestrancomollevartuRustalsiguientenivel.Patronescomunesycaracterísticasdelabibliotecaestándarseránpresentados.Puedesleerdichasseccionesenelordenqueprefieras.

ElLenguajedeProgramacionRust

65RustEfectivo

Page 66: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%LaPilayelMontículo

Comounlenguajedesistemas,Rustoperaaunbajonivel.Siprovienesdeunlenguajedealtonivel,hayalgunosaspectosdeloslenguajesdeprogramacióndesistemasconloscualespuedasnoestarfamiliarizado.Elmasimportanteeselfuncionamientodelamemoria,conlapilayelmontículo.SiestasfamiliarizadoconelcomolenguajescomoCusanasignacióndesdelapila,estecapituloseraunrepaso.Sinoloestas,aprenderásacercadeesteconceptogeneral,peroconunenfoqueRustero.

ManejodememoriaEstosdostérminoshacenreferenciaaelmanejodelamemoria.Lapilayelmontículosonabstraccionesqueayudanadeterminarcuandoasignaryliberarmemoria.

Heaquíunacomparacióndealtonivel:

Lapilaesmuyrápida,yesdedondelamemoriaesasignadapordefectoenRust.Perolaasignacióneslocalaunallamadaafunción,yeslimitadaentamaño.Elmontículoporotrolado,esmaslento,yesasignadoportuprograma.Peroesefectivamentedeuntamañoilimitado,yesglobalmenteaccesible.

LaPilaHablemosacercadeesteprogramaRust:

fnmain(){

letx=42;

}

Esteprogramaposeeunavariable(variablebinding),x.Lamemoriatienequeserasignadadesdealgúnsitio.Rustasignadesdelapilapordefecto,loquesetraduceenquelosvaloresbásicos‘vanalapila’.Pero,quesignificaesto?

Veamos,cuandounafunciónesllamada,algodememoriaesasignadaparasusvariableslocalesyotrainformaciónextra.Dichamemoriaesllamada‘registrodeactivación’(‘stackframe’),paraelpropósitodeestetutorial,ignoraremoslainformaciónextraysoloconsideraremoslasvariableslocalesalasqueestamosasignandomemoria.Asíqueenestecaso,cuandomain()esejecutada,asignamosunenterode32bitsparanuestroregistrodeactivación.Todoestoesmanejadoautomáticamente,comohaspodidover,notuvimosqueescribirningúncódigoRustespecialoalgunaotracosa.

ElLenguajedeProgramacionRust

66LaPilayelMontículo

Page 67: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Cuandolafuncióntermina,suregistrodeactivaciónesliberadoodesasignado.Estoocurredemaneraautomática,notuvimosquehacernadaespecialacá.

Esoestodoparaestesimpleprograma.Loclaveaentenderaquíesquelaasignacióndememoriadesdelapilaesmuy,muyrápida.Debidoaqueconocemosporadelantadotodaslasvariableslocales,podemosobtenertodalamemoriadeunasolavez.Ydebidoaqueladesecharemostodacompleta,podemosdeshacernosdeellamuyrápido,también.

Ladesventajaesquenopodemosmantenervaloresrondandoporallísilosnecesitamosporunperiodomaslargoqueeltiempodevidadeunafunción.Tampocohemoshabladoacercadequesignificaesenombre,‘pila’.Parahacerlonecesitamosunejemploligeramentemascomplejo:

fnfoo(){

lety=5;

letz=100;

}

fnmain(){

letx=42;

foo();

}

Esteprogramatienetresvariablesentotal:dosenfoo(),unaenmain().Aligualqueantes,cuandomain()esllamada,unsoloenteroesasignadoparasuregistrodeactivación.Peroantesquedemostremosqueesloquepasacuandofoo()esllamada,necesitamosvisualizarqueesloqueestapasandoenmemoria.Tusistemaoperativopresentaatuprogramaunavisiónmuysimple:unalistainmensadedirecciones,desde0hastaunnumeromuygrande,querepresentacuantamemoriaRAMposeelamaquina.PorejemplositienesungigabytedeRAM,tusdireccionesirándesde0hasta1,073,741,824,numeroqueprovienede230,elnumerodebytesenungigabyte.

Estamemoriaesunaespeciedearreglogigante:lasdireccionescomienzanenceroyseincrementanhastaelnumerofinal.Entonces,heaquíundiagramadenuestroprimerregistrodeactivación:

Dirección Nombre Valor

0 x 42

Hemoscolocadoaxenladirección0,conelvalor42

Cuandofoo()esllamadaunnuevoregistrodeactivaciónesasignado:

ElLenguajedeProgramacionRust

67LaPilayelMontículo

Page 68: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Dirección Nombre Valor

2 z 100

1 y 5

0 x 42

Debidoaque0fuereservadoparalaprimeraframe,1y2sonusadosparaelregistrodeactivacióndefoo().Lapilacrecehaciaarriba,amedidaquellamamosamasfunciones.

Hayalgunascosasimportantesquedebemosnotaraquí.Losnúmeros0,1y2existensoloparapropósitosilustrativos,ynoposeenningunarelaciónconlosnúmerosqueunacomputadorarealmenteusaría.Enparticular,laseriededireccionesestánseparadasporunnumerodebytes,yesaseparaciónpuedeinclusoexcedereltamañodelvalorqueestasiendoalmacenado.

Despuésquefoo()termina,suregistrodeactivaciónesliberado:

Dirección Nombre Valor

0 x 42

Yluegodespuésdequemain()finaliza,esteultimovalorseva.Fácil!

Esllamadaunapila(‘stack’)debidoaquefuncionacomounapiladeplatos:elprimerplatoquecolocaseselultimoplatoquesacarás.Laspilassonalgunasvecesllamadas‘colasultimoqueentra,primeroquesale’(‘lastin,firstoutqueues’),porestasrazoneselultimovalorquepusisteenlapilaseráelprimeroqueobtendrásdeella.

Probemosunejemplodetresniveles:

ElLenguajedeProgramacionRust

68LaPilayelMontículo

Page 69: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnbar(){

leti=6;

}

fnfoo(){

leta=5;

letb=100;

letc=1;

bar();

}

fnmain(){

letx=42;

foo();

}

Bien,enprimerainstancia,llamamosamain():

Dirección Nombre Valor

0 x 42

Actoseguido,main()llamaafoo():

Dirección Nombre Valor

3 c 1

2 b 100

1 a 5

0 x 42

Luegofoo()llamaabar():

Dirección Nombre Valor

4 i 6

3 c 1

2 b 100

1 a 5

0 x 42

Uff!Nuestrapilaestacreciendo.

ElLenguajedeProgramacionRust

69LaPilayelMontículo

Page 70: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Despuésquebar()termina,suregistrodeactivaciónesliberado,dejandosoloafoo()ymain():

Dirección Nombre Valor

3 c 1

2 b 100

1 a 5

0 x 42

Despuésfoo()termina,dejandosoloamain()

Dirección Nombre Valor

0 x 42

Hemosterminadoentonces.Seentiende?Escomoapilarplatos:agregasaltopeysacasdeel.

ElMontículoAhora,todoestotrabajabien,peronotodofuncionadeesamanera.Algunasveces,necesitaspasarmemoriaentrediferentesfunciones,omantenermemoriavivaporuntiempomayorquelaejecucióndeunafunción.Paraestousamoselmontículo.

EnRust,puedesasignarmemoriadesdeelmontículoconeltipoBox<T>(caja).

Heaquiunejemplo:

fnmain(){

letx=Box::new(5);

lety=42;

}

Acá,loquesucedecuandomain()esllamada:

Dirección Nombre Valor

1 y 42

0 x ??????

Asignamosespacioparadosvariablesenlapila.yes42,comoconocemoshastaahora,peroqueacercadex?Bueno,xesunBox<i32>,ylascajas(boxes)asignanmemoriadesdeelmontículo.Elvalordelacajaencuestiónesunaestructuraqueposeeun

ElLenguajedeProgramacionRust

70LaPilayelMontículo

Page 71: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

apuntadora‘elmontículo’.Cuandocomienzalaejecucióndelafunción,yBox::new()esllamada,estaasignaalgodememoriaparaelmontículoycoloca5allí.Lamemoriaahoraluceasí:

Dirección Nombre Valor

230 5

... ... ...

1 y 42

0 x 230

Tenemos230ennuestracomputadorahipotéticacon1GBdeRAM.Ydebidoaquenuestrapilacrecedesdecero,laformamasfácilparaasignarmemoriaesdesdeelotroextremo.Entoncesnuestroprimervalorestaenellugarmasaltoenlamemoria.Yelvalordelaestructuraenxtieneunapuntadorplano(rawpointer)aellugarquehemosasignadoenelmontículo,entonceselvalordexes230,ladireccióndelamemoriaquehemossolicitado.

Nohemoshabladomuchoacercadequesignificaenrealidadasignaryliberarmemoriaenestoscontextos.Entrarenelprofundodetalledeelloestafueradelalcancedeestetutorial,loimportantearesaltaresqueelmontículonoesunasimplepilaquecrecedesdeelladoopuesto.Tendremosunejemplodeestomasadelanteenellibro,perodebidoaqueelmontículopuedeserasignadoyliberadoencualquierorden,puedeterminarcon‘vacios’.Heaquíundiagramadeladistribucióndelamemoriadeunprogramaquehaestadocorriendoporalgúntiempo:

Dirección Nombre Valor

230 5

(230)-1

(230)-2

(230)-3 42

... ... ...

3 y (230)-3

2 y 42

1 y 42

0 x 230

ElLenguajedeProgramacionRust

71LaPilayelMontículo

Page 72: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Enestecaso,hemosasignadocuatrocosasenelmontículo,perohemosliberadodosdeellas.Hayunvacíoentre230y(230)-3quenoestasiendousadoactualmente.Eldetalleespecificoacercadecomoyporqueestosucededependedelaestrategiausadaparamanejarelmontículo.Diferentesprogramaspuedenusardiferentes‘asignadoresdememoria’(‘memoryallocators’),quesonbibliotecasencargadasdemanejarlaasignacióndememoriaporti.LosprogramasenRustusanjemallocparadichopropósito.

Decualquiermodo,ydevueltaanuestroejemplo.Debidoaqueestamemoriaestaenelmontículo,puedepermanecervivamastiempoquelafunciónquecrealacaja(box).Sinembargo,enestecaso,estonosucede.movingcuandolafuncióntermina,necesitamosliberarelregistrodeactivacióndemain().Box<T>,sinembargo,tienenuntrucobajolamanga:Drop.LaimplementacióndeDropparaBoxliberalamemoriaquehasidoasignadacuandolacajaescreada.Grandioso!Asíquecuandoxseva(saledecontexto),primeroliberalamemoriaasignadadesdeelmontículo:

Dirección Nombre Valor

1 y 42

0 x ??????

moving.Podemoshacerquelamemoriapermanezcavivamastiempotransfiriendolapertenencia(ownership),algunasvecesllamado‘moviendofueradelacaja’(‘movingoutofthebox’).Ejemplosmascomplejosseráncubiertosmasadelante.↩

Luegoelregistrodeactivaciónseva,liberandotodanuestramemoria.

Argumentosyprestamo(borrowing)Hemosllevadoacaboalgunosejemplosbásicosconlapilayelmontículo,peroquehayacercadelosargumentosafuncionesyelpréstamo(borrowing)?HeaquíunpequeñoprogramaRust:

fnfoo(i:&i32){

letz=42;

}

fnmain(){

letx=5;

lety=&x;

foo(y);

}

ElLenguajedeProgramacionRust

72LaPilayelMontículo

Page 73: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Cuandoentramosamain(),lamemorialucedelasiguientemanera:

Dirección Nombre Valor

1 y 0

0 x 5

xesunsimple5,yyesunareferenciaax.Entonces,elvalordeyesladireccióndememoriaenlaquexvive,queenestecasoes0.

Quesucedecuandollamamosafoo()pasandoaycomoargumento?

Dirección Nombre Valor

3 z 42

2 i 0

1 y 0

0 x 5

Losregistrosdeactivaciónnosonsoloparavariableslocales,sontambiénparaargumentos.Enestecaso,necesitamostenerambosi,nuestroargumento,yznuestravariablelocal.iesunacopiadelargumento,y.Debidoaqueelvalordeyes0entonceseseeselvalordei.

Estaesunarazónporlacualtomarprestadaunavariablenoliberaningunamemoria:elvalordelareferenciaessolounapuntadoraunadireccióndememoria.Sinosdeshiciéramosdelamemoriasubyacente,lascosasnoiríandeltodobien.

UnejemplocomplejoBien,vayamosatravésdeesteprogramacomplejopaso-a-paso:

ElLenguajedeProgramacionRust

73LaPilayelMontículo

Page 74: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnfoo(x:&i32){

lety=10;

letz=&y;

baz(z);

bar(x,z);

}

fnbar(a:&i32,b:&i32){

letc=5;

letd=Box::new(5);

lete=&d;

baz(e);

}

fnbaz(f:&i32){

letg=100;

}

fnmain(){

leth=3;

leti=Box::new(20);

letj=&h;

foo(j);

}

Primero,llamamosamain():

Dirección Nombre Valor

230 20

... ... ...

2 j 0

1 i 230

0 h 3

Asignamosmemoriaparaj,i,yh.iestaenelmontículo,esporelloquesuvalorapuntahaciael.

Acontinuation,alfinaldemain(),foo()esllamada:

ElLenguajedeProgramacionRust

74LaPilayelMontículo

Page 75: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Dirección Nombre Valor

230 20

... ... ...

5 z 4

4 y 10

3 x 0

2 j 0

1 i 230

0 h 3

Esasignadoespacioparax,y,yz.Elargumentoxtieneelmismovalorquej,debidoaqueesofueloqueleproporcionamosalafunción.Esunapuntadoraladirección0,puestoquejapuntaah.

Seguidamente,foo()llamaabaz(),pasándolez:

Dirección Nombre Valor

230 20

... ... ...

7 g 100

6 f 4

5 z 4

4 y 10

3 x 0

2 j 0

1 i 230

0 h 3

Hemosasignadomemoriaparafyg.baz()esmuycorta,asíquecuandotermina,nosdeshacemosdesuregistrodeactivación:

ElLenguajedeProgramacionRust

75LaPilayelMontículo

Page 76: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Dirección Nombre Valor

230 20

... ... ...

5 z 4

4 y 10

3 x 0

2 j 0

1 i 230

0 h 3

Después,foo()llamaabar()conxyz:

Dirección Nombre Valor

230 20

(230)-1 5

... ... ...

10 e 9

9 d (230)-1

8 c 5

7 b 4

6 a 0

5 z 4

4 y 10

3 x 0

2 j 0

1 i 230

0 h 3

Terminamosasignandootrovalorenelmontículo,asíquetenemosquerestarunoa230.Esmasfácilescribiresoque1,073,741,823.Encualquiercaso,seteamoslasvariablescomoyaesusual.

Alfinaldebar(),estallamaabaz():

ElLenguajedeProgramacionRust

76LaPilayelMontículo

Page 77: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Dirección Nombre Valor

230 20

(230)-1 5

... ... ...

12 g 100

11 f 9

10 e 9

9 d (230)-1

8 c 5

7 b 4

6 a 0

5 z 4

4 y 10

3 x 0

2 j 0

1 i 230

0 h 3

Conesto,estamosennuestropuntomasprofundo!Wow!Felicitacionesporhaberseguidotodoestoyhaberllegadotanlejos.

Luegobaz()termina,nosdeshacemosdefyg:

ElLenguajedeProgramacionRust

77LaPilayelMontículo

Page 78: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Dirección Nombre Valor

230 20

(230)-1 5

... ... ...

10 e 9

9 d (230)-1

8 c 5

7 b 4

6 a 0

5 z 4

4 y 10

3 x 0

2 j 0

1 i 230

0 h 3

Acontinuación,retornamosdebar().denestecasoesunBox<T>,entoncestambiénliberaaloqueapunta:(230)-1.

Dirección Nombre Valor

230 20

... ... ...

5 z 4

4 y 10

3 x 0

2 j 0

1 i 230

0 h 3

Después,foo()retorna:

ElLenguajedeProgramacionRust

78LaPilayelMontículo

Page 79: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Dirección Nombre Valor

230 20

... ... ...

2 j 0

1 i 230

0 h 3

Entonces,finalmentemain()retorna,locuallimpiaelresto.Cuandoiesliberada(atravésdeDrop)estalimpiaratambiénlorestanteenelmontículo.

Quehacenotroslenguajes?Lamayoríadeloslenguajesconunrecolectordebasuraasignandesdeelmontículopordefecto.Estosignificaquetodoslosvaloresestándentrodecajas(boxed).Existenunnumeroderazonesporlacualesestosehacedeestamanera,peroestánfueradelalcancedeestetutorial.También,existenalgunasoptimizacionesquehacenqueestonosea100%verdadtodoeltiempo.EnvezdeconfiarenlapilayDropparalimpiarlamemoria,elrecolectordebasuraeselencargadodeadministrarelmontículo.

Cualusar?Silapilaesmasrápidaymasfácildeusar,porquenecesitamoselmontículo?UnagranrazónesquelaasignacióndesdelapilasignificaquesolotienessemánticaLIFOparareclamaralmacenamiento.Laasignacióndesdeelmontículoesestrictamentemasgeneral,permitiendoqueelalmacenamientopuedasertomadoyretornadoaelpoolenordenarbitrario,peroconuncostoencomplejidad.

Generalmente,deberíaspreferirasignacióndesdelapila,esporelloqueRustasignadesdelapilapordefecto.ElmodeloLIFOdelapilaesmassimple,anivelfundamental.Estotienedosgrandesimpactos:eficienciaentiempodeejecucióneimpactosemántico.

EficienciaentiempodeEjecucion.Administrarlamemoriaparalapilaestrivial:Lamaquinasimplementeincrementaunsolovalor,elllamado"apuntadoralapila"(“stackpointer”).Laadministracióndememoriaparaelmontículonoloes:Lamemoriaasignadadesdeelmontículoesliberadaenpuntos

ElLenguajedeProgramacionRust

79LaPilayelMontículo

Page 80: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

arbitrarios,ycadabloquedememoriaasignadadesdeelmontículopudeserdeuntamañoarbitrario,eladministradordememoriageneralmentedebetrabajarmuchomasduroparaidentificarmemoriaquepuedaserreusada.

Siquisierassumergirtemasenestetópicoconmayordetalle,estepaperesunamuybuenaintroducción.

ImpactosemanticoStack-allocationimpactstheRustlanguageitself,andthusthedeveloper’smentalmodel.TheLIFOsemanticsiswhatdriveshowtheRustlanguagehandlesautomaticmemorymanagement.Eventhedeallocationofauniquely-ownedheap-allocatedboxcanbedrivenbythestack-basedLIFOsemantics,asdiscussedthroughoutthischapter.Theflexibility(i.e.expressiveness)ofnonLIFO-semanticsmeansthatingeneralthecompilercannotautomaticallyinferatcompile-timewherememoryshouldbefreed;ithastorelyondynamicprotocols,potentiallyfromoutsidethelanguageitself,todrivedeallocation(referencecounting,asusedbyRcandArc,isoneexampleofthis).

LaasignacióndesdelapilaimpactaaRustcomolenguaje,yconelloelmodelomentaldeldesarrollador.LasemánticaLIFOesloqueconducecomoellenguajeRustmanejaelmanejoautomáticodememoria.InclusolaliberacióndeunacajaasignadadesdeelmontículoconunúnicodueñopuedesermanejadaporlasemánticaLIFO,talycomosehadiscutidoenestecapitulo.Laflexibilidad(e.j.expresividad)delasemánticano-LIFOsignificaqueengeneralelcompiladornopuedeinferirdemaneraautomáticayentiempodecompilacióndondelamemoriadeberíaserliberada;tienequeapoyarseenprotocolosdinámicos,potencialmenteexternosaellenguaje,paraefectuarliberacióndememoria(conteodereferencias,comoelusadoenRc<T>yArc<T>,esunejemplo).

Cuandosellevaalextremo,elmayorpoderexpresivodelaasignacióndesdeelmontículovieneacostodebienseasoportesignificativoentiempodeejecución(e.j.enlaformadeunrecolectordebasura)oesfuerzosignificativoporpartedelprogramador(enlaformadellamadasmanualesexplícitasquerequierenverificaciónnoproporcionadaporelcompiladordeRust).

ElLenguajedeProgramacionRust

80LaPilayelMontículo

Page 81: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Pruebas

Probarprogramaspuedeserunaformaefectivademostrarlapresenciadebugs,peroesdesesperanzadamenteinadecuadaparamostrarsuausencia.EdsgerW.Dijkstra,"TheHumbleProgrammer"(1972)

HablaremosacercadecomoprobarcódigoRust.DeloquenoestaremoshablandoesacercadelamaneracorrectadeprobarcódigoRust.Haymuchasescuelasdepensamientoenrelaciónalaformacorrectaeincorrectadeescribirpruebas.Todosesosenfoquesusanlasmismasherramientasbásicas,enestaseccióntemostraremoslasintaxisparahacerusodeellas.

Elatributo testEnesencia,unapruebaenRustesunafunciónqueestaanotadaconelatributotest.VamosacrearunnuevoproyectollamadosumadorconCargo:

$cargonewsumador

$cdadder

Cargogeneraraautomáticamenteunapruebasimplecuandocreasunproyectonuevo.Heaquielcontenidodesrc/lib.rs:

#[test]

fnit_works(){

}

Notael#[test].Esteatributoindicaqueestaesunafuncióndeprueba.Actualmentenotienecuerpo.Peroesoessuficienteparapasar!Podemosejecutarlostestsconcargotest:

ElLenguajedeProgramacionRust

81Pruebas

Page 82: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$cargotest

Compilingsumadorv0.1.0(file:///Users/goyox86/Code/rust/sumador)

Runningtarget/debug/sumador-ba17f4f6708ca3b9

running1test

testit_works...ok

testresult:ok.1passed;0failed;0ignored;0measured

Doc-testssumador

running0tests

testresult:ok.0passed;0failed;0ignored;0measured

Cargocompiloyejecutonuestrostests.Haydosconjuntosdesalidaaquí:unoparalaspruebasquenosotrosescribimos,yotroparalostestsdedocumentación.Hablaremosacercadeestosmastarde.Porahoraveamosestalinea:

testit_works...ok

Notaelit_works.Provienedelnombredenuestrafunción:

fnit_works(){

#}

Tambiénobtenemosunalineaderesumen:

testresult:ok.1passed;0failed;0ignored;0measured

Entonces,porquenuestraspruebasvacíaspasan?Cualquierpruebaquenohagapanic!pasa,ycualquierpruebaquehacepanic!falla.Hagamosfallaranuestraprueba:

#[test]

fnit_works(){

assert!(false);

}

assert!esunamacroproporcionadaporRustlacualtomaunargumento:sielargumentoestrue,nadapasa.Sielargumentoesfalse,assert!hacepanic!.Ejecutemosnuestraspruebasotravez:

ElLenguajedeProgramacionRust

82Pruebas

Page 83: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$cargotest

Compilingsumadorv0.1.0(file:///Users/goyox86/Code/rust/sumador)

Runningtarget/debug/sumador-ba17f4f6708ca3b9

running1test

testit_works...FAILED

failures:

----it_worksstdout----

thread'it_works'panickedat'assertionfailed:false',src/lib.rs:3

failures:

it_works

testresult:FAILED.0passed;1failed;0ignored;0measured

thread'<main>'panickedat'Sometestsfailed',/Users/rustbuild/src/rust-buildbot/slave/stable-dist-rustc-mac/build/src/libtest/lib.rs:

Rustnosindicaquenuestrapruebahafallado:

testit_works...FAILED

Ysereflejaenlalineaderesumen:

testresult:FAILED.0passed;1failed;0ignored;0measured

Tambiénobtenemosunvalorderetornodiferenteacero:

$echo$?

101

Estoesmuyútilparaintegrarcargotestconotrasherramientas.

Podemosinvertirlafalladenuestraspruebasconotroatributo:should_panic:

#[test]

#[should_panic]

fnit_works(){

assert!(false);

}

Estaspruebastendránéxitosihacemospanic!yfallaransisecompletan.Probemos:

ElLenguajedeProgramacionRust

83Pruebas

Page 84: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$cargotest

Compilingsumadorv0.1.0(file:///Users/goyox86/Code/rust/sumador)

Runningtarget/debug/sumador-ba17f4f6708ca3b9

running1test

testit_works...ok

testresult:ok.1passed;0failed;0ignored;0measured

Doc-testssumador

running0tests

testresult:ok.0passed;0failed;0ignored;0measured

Rustproporcionaotramacro,assert_eq!,quecomparadosargumentosparaverificarigualdad:

#[test]

#[should_panic]

fnit_works(){

assert_eq!("Hola","mundo");

}

Estapruebapasaofalla?Debidoalapresenciadelatributoshould_panic,pasa:

$cargotest

Compilingsumadorv0.1.0(file:///Users/goyox86/Code/rust/sumador)

Runningtarget/debug/sumador-ba17f4f6708ca3b9

running1test

testit_works...ok

testresult:ok.1passed;0failed;0ignored;0measured

Doc-testssumador

running0tests

testresult:ok.0passed;0failed;0ignored;0measured

Laspruebasshould_panicpuedenserfrágiles,esdifícilgarantizarquelapruebanofallóporunarazóninesperada.Paraayudarenesto,unparámetroopcionalexpectedpuedeseragregadoaelatributoshould_panic.Lapruebaseaseguraraqueelmensajedeerrorcontengaelmensajeproporcionado.Unaversiónmasseguradelapruebaseria:

ElLenguajedeProgramacionRust

84Pruebas

Page 85: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#[test]

#[should_panic(expected="assertionfailed")]

fnit_works(){

assert_eq!("Hola","mundo");

}

Esofuetodoparalobásico!Escribamosunaprueba'real':

pubfnsuma_dos(a:i32)->i32{

a+2

}

#[test]

fnit_works(){

assert_eq!(4,suma_dos(2));

}

Esteesunusomuycomúndeassert_eq!:llamaralgunafunciónconalgunosargumentosconocidosycompararlasalidadedichallamadaconlasalidaesperada.

Elmodulo testsHayunaformaenlacualnuestroejemplonoesidiomático:lefaltaelmodulotests.Lamaneraidiomáticadeescribirnuestroejemploluceasí:

pubfnsuma_dos(a:i32)->i32{

a+2

}

#[cfg(test)]

modtests{

usesuper::suma_dos;

#[test]

fnit_works(){

assert_eq!(4,suma_dos(2));

}

}

Hayunoscuantoscambiosacá.Elprimeroeslainclusiondeunmodtestsconunatributocfg.Elmodulonospermiteagrupartodasnuestraspruebas,ytambiénnospermitedefinirfuncionesdesoportedesernecesario,todoesonoformapartedenuestrocrate.Elatributo

ElLenguajedeProgramacionRust

85Pruebas

Page 86: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

cfgsolocompilanuestrocódigodepruebassiestuviéramosintentandocorrerlaspruebas.Estopuedeahorrartiempodecompilación,tambiénseaseguraquenuestraspruebasquedencompletamenteexcluidasdeunacompilaciónnormal.

Elsegundocambioesladeclaraciónuse.Debidoaqueestamosenunmodulointerno,necesitamoshacedisponibleanuestrapruebadentrodenuestroámbitoactual.Estopuedesermolestosiposeesunmodulogrande,yesporelloqueescomúnelusodelafacilidadglob.Cambiemosnuestrosrc/lib.rsparaquehagausodeello:

pubfnsuma_dos(a:i32)->i32{

a+2

}

#[cfg(test)]

modtests{

usesuper::*;

#[test]

fnit_works(){

assert_eq!(4,suma_dos(2));

}

}

Notalalineausediferente.Ahoraejecutamosnuestraspruebas:

$cargotest

Compilingsumadorv0.1.0(file:///Users/goyox86/Code/rust/sumador)

Runningtarget/debug/sumador-ba17f4f6708ca3b9

running1test

testtests::it_works...ok

testresult:ok.1passed;0failed;0ignored;0measured

Doc-testssumador

running0tests

testresult:ok.0passed;0failed;0ignored;0measured

Funciona!

Laconvenciónactualesusarelmodulotestsparacontenertuspruebasde"estilo-unitario".Cualquiercosaquesolopruebeunpequeñopedazodefuncionalidadvaaquí.Peroqueacercadelaspruebas"estilo-integracion"?Paraellas,tenemoseldirectoriotests.

ElLenguajedeProgramacionRust

86Pruebas

Page 87: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Eldirectorio testsParaescribirunapruebadeintegración,creemosundirectoriotestsycoloquemosunarchivotests/lib.rsdentro,conelsiguientedecontenido:

externcratesumador;

#[test]

fnit_works(){

assert_eq!(4,sumador::suma_dos(2));

}

Lucesimilaranuestraspruebasanteriores,peroligeramentediferente.Ahoratenemosunexterncratesumadoralprincipio.Estoesdebidoaquelaspruebaseneldirectoriosonuncrateseparado,entoncesdebemosimportarnuestrabiblioteca.Estoestambiénelporquetestsesunlugaridóneoperaescribirtestsdeintegración:estaspruebasusanlabibliotecajustocomocualquierotroconsumidorloharía.

Ejecutemoslas:

$cargotest

Compilingsumadorv0.1.0(file:///Users/goyox86/Code/rust/sumador)

Runningtarget/debug/lib-f71036151ee98b04

running1test

testit_works...ok

testresult:ok.1passed;0failed;0ignored;0measured

Runningtarget/debug/sumador-ba17f4f6708ca3b9

running1test

testtests::it_works...ok

testresult:ok.1passed;0failed;0ignored;0measured

Doc-testssumador

running0tests

testresult:ok.0passed;0failed;0ignored;0measured

Ahoratenemostressecciones:nuestraspruebasanteriorestambiénfueronejecutadas,juntoconlanuevapruebadeintegración.

ElLenguajedeProgramacionRust

87Pruebas

Page 88: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Esofuetodoparaeldirectoriotests.Elmodulotestsnoesnecesarioaquí,debidoaqueelmodulocompletoestadedicadoapruebas.

Finalmenteechemosunvistazoaesatercerasección:pruebasdedocumentación.

PruebasdedocumentaciónNadaesmejorquedocumentaciónconejemplos.Nadaespeorqueejemplosquenofuncionan,debidoaqueelcódigoacambiadodesdequeladocumentaciónfueescrita.Respectoaesto,Rustsoportalaejecuciónautomáticadelosejemplospresentesentudocumentación.Heaquíunsrc/lib.rspulidoconejemplos:

//!The`adder`crateprovidesfunctionsthataddnumberstoothernumbers.

//!

//!#Examples

//!

//!

//!assert_eq!(4,adder::add_two(2));//!```

///Thisfunctionaddstwotoitsargument.//////#Examples/////////useadder::add_two;//////assert_eq!(4,add_two(2));///pubfnadd_two(a:i32)->i32{a+2}

[cfg(test)]modtests{usesuper::*;

#[test]

fnit_works(){

assert_eq!(4,add_two(2));

}

}

ElLenguajedeProgramacionRust

88Pruebas

Page 89: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Notaladocumentaciónaniveldemodulocon`//!`yladocumentaciónaniveldefuncióncon`///`.LadocumentacióndeRustsoportaMarkdownencomentariosygraves(\`\`\`)triplesdelimitanbloquesdecódigo.Esconvencionalincluirlasección`#Examples`,exactamenteasi,seguidaporlosejemplos.

Ejecutemoslaspruebasnuevamente:

```bash

$cargotest

Compilingsumadorv0.1.0(file:///Users/goyox86/Code/rust/sumador)

Runningtarget/debug/lib-f71036151ee98b04

running1test

testit_works...ok

testresult:ok.1passed;0failed;0ignored;0measured

Runningtarget/debug/sumador-ba17f4f6708ca3b9

running1test

testtests::it_works...ok

testresult:ok.1passed;0failed;0ignored;0measured

Doc-testssumador

running2tests

test_0...ok

testsuma_dos_0...ok

testresult:ok.2passed;0failed;0ignored;0measured

Ahoratenemoslostrestiposdepruebascorriendo!Notalosnombresdelaspruebasdedocumentación:el_0esgeneradoparalapruebadelmodulo,ysuma_dos_0paralapruebadefunción.Estosnúmerosseautoincrementaranconnombrescomosuma_dos_1amedidaquemasejemplossonagregados.

ElLenguajedeProgramacionRust

89Pruebas

Page 90: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%CompilaciónCondicional

Rustposeeunatributoespecial,#[cfg],quetepermitecompilarcódigobasadoenunaopciónproporcionadaalcompilador.Tienedosformas:

#[cfg(foo)]

#fnfoo(){}

#[cfg(bar="baz")]

#fnbar(){}

Tambiénposeealgunoshelpers:

#[cfg(any(unix,windows))]

#fnfoo(){}

#[cfg(all(unix,target_pointer_width="32"))]

#fnbar(){}

#[cfg(not(foo))]

#fnnot_foo(){}

Loscualespuedenseranidadosdemaneraarbitraria:

#[cfg(any(not(unix),all(target_os="macos",target_arch="powerpc")))]

#fnfoo(){}

Paraactivarodesactivarestosswitches,siestasusandoCargo,seconfiguranenlasección[features]detuCargo.toml

[features]

#Nofeaturespordefecto

default=[]

#Elfeature“secure-password”dependeenelpaquetebcrypt.

secure-password=["bcrypt"]

Cuandohacemosesto,Cargopasaunaopciónarustc:

--cfgfeature="${feature_name}"

Lasumadeesasopcionescfgdeterminaracualessonactivadas,yenconsecuencia,cualcódigoseracompilado.Tomemosestecódigo:

ElLenguajedeProgramacionRust

90CompilaciónCondicional

Page 91: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#[cfg(feature="foo")]

modfoo{

}

Silocompilamosconcargobuild--features"foo",Cargoenviaralaopción--cfgfeature="foo"arustc,ylasalidatendráraelmodfoo.Sicompilamosconuncargobuildnormal,ningunaopciónextraseraproporcionada,ydebidoaesto,ningúnmodulofooexistirá.

cfg_attrTambiénpuedesconfigurarotroatributobasadoenunavariablecfgconcfg_attr:

#[cfg_attr(a,b)]

#fnfoo(){}

Seralomismoque#[b]siaesconfiguradoporunatributocfg,ynadadecualquierotramanera.

cfg!Laextensiondesintaxistepermitetambiénusarestetipodeopcionesencualquierotropuntodetucódigo:

ifcfg!(target_os="macos")||cfg!(target_os="ios"){

println!("ThinkDifferent!");

}

Estosseránreemplazadoportrueofalseentiempodecompilación,dependiendoenlasopcionesdelaconfiguración.

ElLenguajedeProgramacionRust

91CompilaciónCondicional

Page 92: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Documentación

LadocumentaciónesunaparteimportantedecualquierproyectodesoftwareyunciudadanodeprimeraclaseenRust.HablemosacercadelasherramientasqueRustteproporcionaparadocumentartusproyectos.

AcercaderustdocLadistribucióndeRustincluyeunaherramienta,rustdoc,encargadadegenerarladocumentación.rustdocestambiénusadaporCargoatravésdecargodoc.

Ladocumentaciónpuedesergeneradadedosformas:desdeelcódigofuente,odesdearchivosMarkdown.

DocumentandocódigofuenteLaprincipalformadedocumentarunproyectoRustesatravésdelaanotacióndelcódigofuente.Paraestepropósito,puedesusarcomentariosdedocumentación:

///Construyeunnuevo`Rc`.

///

///#Examples

///

///

///usestd::rc::Rc;//////letcinco=Rc::new(5);///```pubfnnew(value:T)->Rc{//laimplementaciónvaaqui}

Elcódigoanteriorgeneradocumentaciónquelucecomo[esta][rc-new](ingles).Hedejadolaimplementaciónporfuera,conuncomentarioregularensulugar.Esaeslaprimeracosaaresaltaracercadeestaanotación:usa`///`,envezde`//`.Elslashtripleindicaqueesuncomentariodedocumentación.

LoscomentariosdedocumentaciónestánescritosenformatoMarkdown.

Rustmantieneunregistrodedichoscomentarios,registroqueusaalmomentodegenerarladocumentación.Estoesimportantecuandosedocumentancosascomoenumeraciones(enums):

```rust

///Eltipo`Option`.Vea[ladocumentaciónaniveldemodulo](../)paramasinformación.

enumOption<T>{

///Ningúnvalor

None

///Algúnvalor`T`

Some(T),

}

ElLenguajedeProgramacionRust

92Documentación

Page 93: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Loanteriorfunciona,peroesto,no:

///Eltipo`Option`.Vea[ladocumentaciónaniveldemodulo](../)paramasinformación.

enumOption{

None,///Ningúnvalor

Some(T),///Algúnvalor`T`

}

Obtendrásunerror:

hola.rs:4:1:4:2error:expectedident,found`}`

hola.rs:4}

^

Estedesafortunadoerrorescorrecto:loscomentariosdedocumentaciónaplicansoloaloqueestedespuésdeellos,ynohaynadadespuésdelultimocomentario.

Escribiendocomentariosdedocumentación

Decualquiermodo,cubramoscadapartedeestecomentarioendetalle:

///Construyeunnuevo`Rc<T>`.

#fnfoo(){}

Laprimeralineadeuncomentariodedocumentacióndebeserunresumencortodesusfuncionalidad.Unaoración.Sololobásico.Dealtonivel.

///

///Otrosdetallesacercadelaconstrucciónde`Rc<T>`s,quizásdescribiendosemántica

///complicada,talvezopcionesadicionales,cualquiercosaextra.

///

#fnfoo(){}

Nuestroejemplooriginalsoloteniaunalineaderesumen,perosihubiésemostenidomascosasquedecir,pudimoshaberagregadomasexplicaciónenunpárrafonuevo.

Seccionesespeciales

///#Examples

#fnfoo(){}

ElLenguajedeProgramacionRust

93Documentación

Page 94: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Acontinuaciónestánlasseccionesespeciales.Estassonindicadasconunacabecera,#.Haytrestiposdecabeceraqueseusancomúnmente.Estosnosonsintaxisespecial,soloconvención,porahora.

///#Panics

#fnfoo(){}

Maloseirrecuperablesusosdeunafunción(e.j.Erroresdeprogramación)enRustsonusualmenteindicadosporpánicos(panics),loscualesmatanelhiloactualcomomínimo.Situfunciónposeeuncontratonotrivialcomoeste,queesdetectado/impuestoporpánicos,documentarloesmuyimportante.

///#Failures

#fnfoo(){}

SitufunciónométodoretornaunResult<T,E>,entoncesdescribirlascondicionesbajolascualesretornaErr(E)esalgobuenoporhacer.EstoesligeramentemenosimportantequePanics,aconsecuenciadequeescodificadoenelsistemadetipos,peroesaun,algoqueserecomiendahacer.

///#Safety

#fnfoo(){}

Situfunciónesunsafe(insegura),deberíasexplicarcualessonlasinvariantesquedebensermantenidasporelllamador.

///#Examples

///

///

///usestd::rc::Rc;//////letcinco=Rc::new(5);///```

fnfoo(){}

ElLenguajedeProgramacionRust

94Documentación

Page 95: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Tercero,`Examples`,incluyeunoomasejemplosdelusodetufunciónométodo,ytususuariostequerrán.Estosejemplosvandentrodeanotacionesdebloquesdecódigo,deloscualeshablaremosenunmomento,puedentenermasdeunasección:

```rust

///#Examples

///

///Patrones`&str`simples:

///

///

///letv:Vec<&str>="Maryteniauncorderito".split('').collect();///assert_eq!(v,vec!["Mary","tenia","un","corderito"]);/////////Patronesmascomplejosconlambdas://///////letv:Vec<&str>="abc1def2ghi".split(|c:char|c.is_numeric()).collect();///assert_eq!(v,vec!["abc","def","ghi"]);///```

fnfoo(){}

Discutamoslosdetallesdeesosbloquesdecódigo.

####Anotacionesdebloquesdecódigo

ParaescribiralgunacódigoRustenuncomentario,usalosgravestriples:

```rust

///

///println!("Hola,mundo");///```

fnfoo(){}

SiquierescódigoquenoseaRust,puedesagregarunaanotación:

```rust

///```c

///printf("Hola,mundo\n");

///

ElLenguajedeProgramacionRust

95Documentación

Page 96: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnfoo(){}

Lasintaxisdeestasecciónseraresaltadadeacuerdoallenguajequeestésmostrando.Sisoloestasmostrandotextoplano,usa`text`.

Acá,esimportanteelegirlaanotacióncorrecta,debidoaque`rustdoc`lausadeunamanerainteresante:Puedeserusadaparaprobartusejemplos,detalmaneraquenosevuelvanobsoletosconeltiempo.SitienesalgúncódigoCpero`rustdoc`piensaqueesRust,esporqueolvidastelaanotación,`rustdoc`sequejaraalmomentodetratardegenerarladocumentación.

##Documentacióncomopruebas

Discutamosnuestradocumentacióndeejemplo:

```rust

///

///println!("Hola,mundo");///```

fnfoo(){}

Notarasquenonecesitasuna`fnmain()`oalgomas.`rustdoc`agregaraunmain()automáticamentealrededordetucódigo,yenellugarcorrecto.Porejemplo:

```rust

///

///usestd::rc::Rc;//////letcinco=Rc::new(5);///```

fnfoo(){}

Seconvertiráenlaprueba:

```rust

fnmain(){

usestd::rc::Rc;

letcinco=Rc::new(5);

}

Heaquíelalgoritmocompletoquerustdocusaparapost-procesarlosejemplos:

1. Cualquieratributo#![foo]sobranteesdejadointactocomoatributodelcrate.

ElLenguajedeProgramacionRust

96Documentación

Page 97: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

2. Algunosatributoscomunessoninsertados,incluyendounused_variables,unused_assignments,unused_mut,unused_attributes,ydead_code.Ejemplospequeñosocasionalmentedisparanestoslints.

3. Sielejemplonocontieneexterncrate,entonceselexterncrate<micrate>;esinsertado.

4. Finalmente,sielejemplonocontienefnmain,eltextoesenvueltoenfnmain(){tu_codigo}

Algunasveces,todoestonoessuficiente.Porejemplo,todosestosejemplosdecódigocon///delosquehemosestadohablando?Eltextoplano:

///Algodedocumentación.

#fnfoo(){}

Lucediferentealasalida:

///Algodedocumentación.

#fnfoo(){}

Si,escorrecto:puedesagregarlineasquecomiencencon#,yestasseráneliminadasdelasalida,peroseránusadasenlacompilacióndetucódigo.Puedesusarestocomoventaja.Enestecaso,loscomentariosdedocumentaciónnecesitanaplicaraalgúntipodefunción,entoncessiquieromostrarsolouncomentariodedocumentación,necesitoagregarunapequeñadefinicióndefuncióndebajo.Almismotiempo,estaallísoloparasatisfaceralcompilador,demaneratalqueesconderlahaceelejemplomaslimpio.Puedesusarestatécnicaparaexplicarejemplosmaslargosendetalle,preservandoaunlacapacidaddetudocumentaciónparaserprobada.Porejemplo,estecódigo:

letx=5;

lety=6;

println!("{}",x+y);

Heaquíunaexplicación,renderizada:

Primero,asignamosaxelvalordecinco:

letx=5;

#lety=6;

#println!("{}",x+y);

Acontinuación,asignamosseisay:

ElLenguajedeProgramacionRust

97Documentación

Page 98: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#letx=5;

lety=6;

#println!("{}",x+y);

Finalmente,imprimimoslasumadexyy:

#letx=5;

#lety=6;

println!("{}",x+y);

Heaquílamismaexplicación,entextoplano:

Primero,asignamosaxelvalordecinco:

letx=5;

#lety=6;

#println!("{}",x+y);

Acontinuación,asignamosseisay:

#letx=5;

lety=6;

#println!("{}",x+y);

Finalmente,imprimimoslasumadexyy:

#letx=5;

#lety=6;

println!("{}",x+y);

Alrepetirtodaslaspartesdelejemplo,puedesasegurartequetuejemploauncompila,mostrandosololaspartesrelevantesatuexplicación.

Documentandomacros

Heaquíunejemplodeladocumentaciónaunamacro:

///Panicconunmensajeproporcionadoamenosquelaexpressionseaevaluadaatrue.

///

///#Examples

///

///

ElLenguajedeProgramacionRust

98Documentación

Page 99: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

///##[macro_use]externcratefoo;///#fnmain(){///panic_unless!(1+1==2,“Lasmathematicasestanrotas.”);///#}/////////should_panic///##[macro_use]externcratefoo;///#fnmain(){///panic_unless!(true==false,“Yoestoyroto.”);///#}///```

[macro_export]macro_rules!panic_unless{($condition:expr,$($rest:expr),+)=>({if!$condition{panic!($($rest),+);}});}

fnmain(){}

Notarastrescosas:necesitamosagregarnuestropropialinea`externcrate`,detalmaneraquepodamosagregarelatributo`#[macro_use]`.Segundo,necesitaremosagregarnuestrapropia`main()`.Finalmente,unusojuiciosode`#`paracomentaresasdoscosas,demaneraquenossemuestrenenlasalida.

###Ejecutandopruebasdedocumentación

Paracorrerlaspruebaspuedes:

```bash

$rustdoc--testruta/a/mi/crate/root.rs

$cargotest

Correcto,cargotestpruebaladocumentaciónembebidatambién.Sinembargo,cargotest,noprobaracratesbinarios,solobibliotecas.Estodebidoalaformaenlaquerustdocfunciona:enlazaconlabibliotecaaserprobada,peroenelcasodeunbinario,nohaynadaalocualenlazar.

Hayunaspocasanotacionesmasquesonútilesparaayudararustdocahacerlacosacorrectacuandopruebastucódigo:

///```ignore

///fnfoo(){

///

fnfoo(){}

ElLenguajedeProgramacionRust

99Documentación

Page 100: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Ladirectiva`ignore`lediceaRustqueignoreelcodigo.Estaeslaformaquecasinuncaquerrás,pueseslamasgenérica.Ensulugar,consideraelanotarcon`text`denosercodigo,ousar`#`sparaobtenerunejemplofuncionalquesolomuestralapartequeteinteresa.

```rust

///```should_panic

///assert!(false);

///

fnfoo(){}

`should_panic`ledicea`rustdoc`queelcódigodebecompilarcorrectamente,perosinlanecesidaddepasarunapruebademanerasatisfactoria.

```rust

///```no_run

///loop{

///println!("Hola,mundo");

///}

///

fnfoo(){}

Elatributo`no_run`compilaratucódigo,peronoloejecutara.Estoesimportanteparaejemploscomo"Heaquícomoiniciarunserviciodered,"elcualdebesasegurartequecompile,peropodríacausaruncicloinfinito!

###Documentandomódulos

Rustposeeotrotipodecomentariodedocumentación,`//!`.Estecomentarionodocumentaelsiguienteitem,estecomentaelitemqueloencierra.Enotraspalabras:

```rust

modfoo{

//!Estaesdocumentationparaelmodulo`foo`.

//!

//!#Examples

//...

}

Esaquíendondeveras//!usadomasamenudo:paradocumentacióndemódulos.Sitienesunmoduloenfoo.rs,frecuentementealaabrirsucódigoverasesto:

ElLenguajedeProgramacionRust

100Documentación

Page 101: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

//!Unmoduloparausar`foo`s.

//!

//!Elmodulo`foo`contieneunmontondefuncionalidadblablabla

Estilodecomentariosdedocumentación

EchaunvistazoaelRFC505paraunlistadocompletodeconvencionesacercadelestiloyformatodeladocumentación(ingles)

OtradocumentaciónTodoestecomportamientofuncionaenarchivosnoRusttambién.DebidoaqueloscomentariossonescritosenMarkdown,frecuentementesonarchivos.md.

CuandoescribesdocumentaciónenarchivosMarkdown,nonecesitasprefijarladocumentaciónconcomentarios.Porejemplo:

///#Examples

///

///

///usestd::rc::Rc;//////letcinco=Rc::new(5);///```

fnfoo(){}

essolo

~~~markdown

#Examples

usestd::rc::Rc;

letcinco=Rc::new(5);

ElLenguajedeProgramacionRust

101Documentación

Page 102: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

~~~

cuandoestaenunarchivoMarkdown.Solohayundetalle,losarchivosmarkdownnecesitanteneruntitulocomoeste:

```markdown

%Titulo

Estaesladocumentacióndeejemplo

Estalinea%deberestarubicadaenlaprimeralineadelarchivo.

atributosdocAunnivelmasprofundo,loscomentariosdedocumentaciónsonotraformadeescribiratributosdedocumentación:

///this

#fnfoo(){}

#[doc="this"]

#fnbar(){}

sonlomismoqueestos:

//!this

#![doc="///this"]

Noverasfrecuentementeesteatributosiendousadoparaescribirdocumentación,peropuedeserutilcuandoseestencambiandociertasopciones,oescribiendounamacro.

Re-exports

rustdocmostraraladocumentaciónparaunre-exportpublicoenamboslugares:

externcratefoo;

pubusefoo::bar;

Loanteriorcrearadocumentaciónparabardentrodeladocumentaciónparaelcratefoo,asícomoladocumentaciónparatucrate.Seralamismadocumentaciónenamboslugares.

ElLenguajedeProgramacionRust

102Documentación

Page 103: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Estecomportamientopuedesersuprimidoconno_inline:

externcratefoo;

#[doc(no_inline)]

pubusefoo::bar;

ControlandoHTML

PuedescontrolaralgunosaspectosdeelHTMLquerustdocgeneraatravésdelaversión#![doc]delatributo:

#![doc(html_logo_url="http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",

html_favicon_url="http://www.rust-lang.org/favicon.ico",

html_root_url="http://doc.rust-lang.org/")]

Estoconfiguraunaspocasopciones,conunlogo,favicon,yURLraíz.

Opcionesdegeneraciónrustdoctambiéncontieneunaspocasopcionesenlalineadecomandos,paramaspersonalización:

--html-in-headerFILE:incluyeelcontenidodeFILEalfinaldelasección<head>...</head>.--html-before-contentFILE:incluyeelcontenidodeFILEdespuésde<body>,antesdelcontenidorenderizado(incluyendolabarradebúsqueda).--html-after-contentFILE:incluyeelcontenidodeFILEdespuésdetodoelcontenidorenderizado.

NotadeseguridadElMarkdownenloscomentariosdedocumentaciónespuestosinprocesarenlapaginafinal.SecuidadosoconHTMLliteral:

///<script>alert(document.cookie)</script>

#fnfoo(){}

ElLenguajedeProgramacionRust

103Documentación

Page 104: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Iteradores

Hablemosdeciclos.

RecuerdaselciclofordeRust?Heaquiunejemplo:

forxin0..10{

println!("{}",x);

}

AhoraquesabesmasRust,podemoshablarendetalleacercadecomoestecódigofunciona.Losrangos(el0..10)soniteradores.Uniteradoresalgoenloquepodemosllamarelmétodo.next()repetitivamente,yeliteradornosproporcionaunasecuenciadeelementos.

Porejemplo:

letmutrango=0..10;

loop{

matchrango.next(){

Some(x)=>{

println!("{}",x);

},

None=>{break}

}

}

Creamosunenlace(unavariable)aelrango,nuestroiterador.Luegoiteramosmedianteelcicloloop,conunmatchinterno.Dichomatchusaelresultadoderango.next(),quenosproporcionaunareferenciaaelsiguientevaloreneliterador.nextretornaunOption<i32>,enestecaso,queseráSome(i32)cuandotenemosunvaloryNonecuandonosquedemossinvalores.SiobtenemosSome(i32),loimprimimos,ysiobtenemosNone,rompemoselciclo,saliendodeelatravésdebreak.

Esteejemplodecódigoesbásicamenteelmismoquenuestraversiondeuncicloforfor.Elcicloforessolounaformapracticadeescribirunaconstrucciónloop/match/break.

Sinembargo,losciclosfornosonlaúnicacosaqueusaiteradores.EscribirtupropioiteradorimplicaimplementareltraitIterator.Sibienhacerloestafueradelámbitodeestaguía,Rustproveeaunnumerodeiteradoresútilesparallevaracabodiversastareas.Antesdehablardeeso,debemoshablaracercadeunanti-patron.Dichoanti-patronesusarrangosdelamaneraexpuestaanteriormente.

ElLenguajedeProgramacionRust

104Iteradores

Page 105: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Si,acabamosdehablaracercadecuancoolsonlosrangos.Perosontambiénmuyprimitivos.Porejemplo,sinecesitamositeraratravésdelcontenidodeunvector,podríamosestartentadosaescribiralgocomoesto:

letnums=vec![1,2,3];

foriin0..nums.len(){

println!("{}",nums[i]);

}

Estonoesestrictamentepeorqueusaruniterador.Sepuedeiterarenvectoresdirectamente,escribeesto:

letnums=vec![1,2,3];

fornumin&nums{

println!("{}",num);

}

Haydosrazonesparahacerlodeestamanera.Primero,expresaloquequeremosdemaneramasdirecta.Iteramosatravésdelvectorcompleto,envezdeiteraratravésdeindicesparaluegoindexarelvector.Segundo,estaversionesmaseficiente:enlaprimeraversiontendremoschequeosdelimitesextradebidoaqueusaindexado,nums[i].Enelsegundoejemploydebidoaqueconeliteradorcedemosunareferenciaacadaelementoalavez,hohaychequeodelimites.Estoesmuycomúneniteradores:podemosignorarchequeosdelimitesinnecesarios,sabiendoalmismotiempoqueestamosseguros.

Hayotrodetalleaquíquenoestael100%clarodebidoaelfuncionamientoprintln!.numesdetipo&i32.Unareferenciaauni32,nouni32.println!manejaeldereferenciamientopornosotros,esporelloquenolovemos.Estecódigotambiénescorrecto:

letnums=vec![1,2,3];

fornumin&nums{

println!("{}",*num);

}

Ahoraestamosdereferenciandoanumdeformaexplicita.Porque&numsnosdareferencias?Primeramente,porquelosolicitamosdemaneraexplicitacon&.Segundo,sinosdieraladataensimisma,tendríamosqueserdueñosdeella,locualimplicaríala

ElLenguajedeProgramacionRust

105Iteradores

Page 106: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

creacióndeunacopiadeladataparadespuésdarnosesacopia.Conreferencias,soloestamoshaciendounpréstamo('borrowing')deunareferenciaaladata,yporellosolopasamosunareferencia,sinnecesidaddetransferirlapertenencia.

Entonces,ahoraquehemosestablecidoquelosrangosavecesnosonloquequeremos,hablemosdeloqueremos.

Haytresampliasclasesdecosasquesonrelevantes:iteradores,adaptadoresdeiteradoresyconsumidores.Heaquíalgunasdefiniciones:

iteradoresproporcionanunasequenciadevalores.adaptadoresdeiteradoresoperanenuniterador,produciendounnuevoiteradorconunasecuenciadiferentedesalida.consumidoresoperanenuniterador,produciendounconjuntofinaldevalores.

Hablemosprimeramenteacercadelosconsumidores,debidoaqueyahemosvistouniterador,losrangos.

ConsumidoresUnconsumidoroperaenuniterador,retornandoalgúntipodevalorovalores.Elconsumidormascomúnescollect().Estecódigonocompila,peromuestralaintención:

letuno_hasta_cien=(1..101).collect();

Comopuedesver,llamamoscollect()eneliterador.collect()tomatantosvalorescomoeliteradorleproporcione,retornandounacolecciónderesultados.Entonces,porqueestecódigonocompilara?Rustnopuededeterminarquetipodecosasquieresrecolectar,yesporellonecesitashacerlesaber.Estaeslaversionquecompila:

letuno_hasta_cien=(1..101).collect::<Vec<i32>>();

Sirecuerdas,lasintaxis::<>tepermitedarunaindicioacercadeltipo,ennuestrocasoestamosdiciendoquequeremosunvectordeenteros.Nosiempreesnecesariousareltipocompleto._tepermitirádarunindicioparcialacercadeltipo:

letuno_hasta_cien=(1..101).collect::<Vec<_>>();

Estodice"RecolectaenunVec<T>,porfavor,peroinfierequeesTpormi."._esporestarazónllamadoalgunasveces"marcadordeposicióndetipo".

ElLenguajedeProgramacionRust

106Iteradores

Page 107: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

collect()eselconsumidormascomún,perohayotros.find()esunodeellos:

letmayores_a_cuarenta_y_dos=(0..100)

.find(|x|*x>42);

matchmayores_a_cuarenta_y_dos{

Some(_)=>println!("Tenemosalgunosnúmeros!"),

None=>println!("Noseencontraronnúmeros:("),

}

findrecibeunclosure,ytrabajaenunareferenciaacadaelementodeuniterador.Dichoclosureretornatruesielelementoeselqueestamosbuscandoyfalsedelocontrario.Debidoaquepodríamosnoencontrarunelementoquesatisfaganuestrocriterio,findretornaunOptionenlugardeunelemento.

Otroconsumidorimportanteesfold.Luceasi:

letsuma=(1..4).fold(0,|suma,x|suma+x);

fold(base,|acumulador,elemento|...).Tomadosargumentos:elprimeroesunelementollamadobase.Elsegundoesunclosurequeasuveztomadosargumentos:elprimeroesllamadoelacumulador,yelsegundoesunelemento.Encadaiteración,elclosureesllamado,yelresultadoesusadocomoelvalordelacumuladorenlasiguienteiteración.Enlaprimeraiteración,labaseeselvalordelacumulador.

Bien,esoesunpococonfuso.Examinemoslosvaloresdetodaslascosasenesteiterador:

base acumulador elemento resultadodelclosure

0 0 1 1

0 1 2 3

0 3 3 6

Hemosllamadoafold()conestosargumentos:

#(1..4)

.fold(0,|suma,x|suma+x);

Entonces,0esnuestrabase,sumaesnuestroacumulador,yxesnuestroelemento.Enlaprimeraiteración,asignamossuma0yxeselprimerelementodenuestrorango,1.Despuéssumamossumyxloquenosda0+1=1.Enlasegundaiteración,esevalorseconvierteenelvalordenuestroacumulador,sum,yelelementoeselsegundoelementodelrango,2.1+2=3ydeigualmaneraseconvierteenelvalordel

ElLenguajedeProgramacionRust

107Iteradores

Page 108: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

acumuladorparalaultimaiteración.Enesaiteración,xeselultimoelemento,3,y3+3=6,resultadofinalparanuestrosuma.1+2+3=6,eseeselresultadoqueobtenemos.

Whew.foldpuedeserunpocoextrañoaprimeravista,perounavezhaceclick,puedesusarloentodoslados.Cadavezquetengasunalistadecosas,ynecesitesunúnicoresultado,foldesapropiado.

Losconsumidoressonimportantesdebidoaunapropiedadadicionaldelositeradoresdelaquenohemoshabladotodavia:pereza(laziness).Hablemosmasacercadelositeradoresyverasporquelosconsumidoressonimportantes.

IteradoresComohemosdichoantes,uniteradoresalgoenloquepodemosllamarelmétodo.next()repetidamente,yestenosdevuelveunasecuenciadeelementos.Debidoaquenecesitamosllamaraelmétodo,lositeradorespuedenserperezososynogenerartodoslosvaloresporadelantado.Estecódigo,porejemplo,nogeneralosnúmeros1-99.Ensulugarcreaunvalorquerepresentalasecuencia:

letnums=1..100;

Debidoaquenohicimosnadaconelrango,estenogenerolasecuencia.Agreguemosunconsumidor:

letnums=(1..100).collect::<Vec<i32>>();

Ahoracollect()requeriráqueelrangoproveaalgunosnúmeros,yenconsecuenciatendraquellevaracabolalabordegenerarlasecuencia.

Losrangossonunadelasdosformasbásicasdeiteradoresqueveras.Laotraesiter().iter()puedetransformarunvectorenuniteradorsimplequeproporcionaunelementoalavez:

letnums=vec![1,2,3];

fornuminnums.iter(){

println!("{}",num);

}

ElLenguajedeProgramacionRust

108Iteradores

Page 109: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Estosdositeradoresbásicosdeberianserdeutilidad.Existeniteradoresmasavanzados,incluyendoaquellosquesoninfinitos.

Suficienteacercadeiteradores,losadaptadoresdeiteradoressonelultimoconceptorelacionadoaiteradoresalquedebemoshacermención.Hagamoslo!

AdaptadoresdeiteradorLosadaptadoresdeiteradorestomanuniteradorylomodificandealgunamanera,produciendounonuevo.Elmassimpleesllamadomap:

(1..100).map(|x|x+1);

mapesllamadoenotroiterador,mapproduceuniteradornuevoenelquecadareferenciaaunelementoposeeelclosurequesehaproporcionadocomoargumento.Elcódigoanteriornosdarálosnúmeros2-100,Bueno,casi!Sicompilaselejemplo,obtendrásunaadvertencia:

warning:unusedresultwhichmustbeused:iteratoradaptorsarelazyand

donothingunlessconsumed,#[warn(unused_must_use)]onbydefault

(1..100).map(|x|x+1);

^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Laperezaatacadenuevo!Eseclosurenuncaseejecutara.Esteejemplonoimprimeningúnnumero:

(1..100).map(|x|println!("{}",x));

Siestasintentantoejecutarunclosureenuniteradorparaobtenersusefectoscolaterales(side-effects)usaunfor.

foriin(1..).take(5){

println!("{}",i);

}

Estoimprimira:

ElLenguajedeProgramacionRust

109Iteradores

Page 110: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

1

2

3

4

5

filter()esunadaptadorquetomaunclosurecomoargumento.Dichoclosureretornatrueofalse.Elnuevoiteradorquefilter()producesoloelementosparalosqueelclosureretornatrue:

foriin(1..100).filter(|&x|x%2==0){

println!("{}",i);

}

Estoimprimirátodoslosnúmerosparesentreunoycien.(Notaquedebidoaquefilternoconsumeloselementosqueestánsiendoiterados,aesteselepasaunareferenciaacadaelemento,debidoaello,elpredicadousaelpatron&xparaextraerelentero.)

(1..)

.filter(|&x|x%2==0)

.filter(|&x|x%3==0)

.take(5)

.collect::<Vec<i32>>();

Loanteriorteunvectorconteniendo6,12,18,24,y30.

Estaesunapequeñamuestradelascosasenlascualeslositeradores,adaptadoresdeiteradores,yconsumidorespuedenayudarte.Existeunavariedaddeiteradoresrealmenteútiles,juntoalhechoquepuedesescribirtuspropios.Lositeradoresproporcionanunamanerasegurayeficientedemanipulartodotipodelistas.Sonunpocoinusualesaprimeravista,perosijuegasunpococonellos,quedarasenganchado.Paraunalistadelosdiferentesiteradoresyconsumidoresechaunvistazoaladocumentaciondelmoduloiterator(ingles).

ElLenguajedeProgramacionRust

110Iteradores

Page 111: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Concurrencia

Laconcurrenciayelparalelismosondostópicosincreíblementeimportantesenlascienciasdelacomputación,tambiénsonuntópicocalienteenlaindustriahoyendía.Lascomputadorascadavezposeenmasymasnúcleos,aunasí,todavíaalgunosdesarrolladoresnoestánpreparadosparautilizarnoscompletamente.

LaseguridadenelmanejodememoriadeRusttambiénaplicaasuhistoriadeconcurrencia.Inclusolosprogramasconcurrentesdebensersegurosenelmanejodememoria,sincondicionesdecarrera.ElsistemadetiposdeRustestaalaalturadeldesafío,ytedotadepoderosasvíaspararazonaracercadecódigoconcurrenteentiempodecompilación.

AntesdequehablemosdelascaracterísticasdeconcurrenciaquevienenconRust,esimportanteentenderalgo:Rustesdebajonivel,suficientementebajoalpuntoquetodasestasfacilidadesestánimplementadasenlabibliotecaestándar.EstosignificaquesinotegustaalgúnaspectodelamaneraenlaqueRustmanejalaconcurrencia,puedesimplementarunaformaalternativadehacerlo.mioesunvivoejemplodeesteprincipioenacción.

Bases:SendySyncLaconcurrenciaesalgosobreloqueesdifícilrazonar.EnRusttenemosunpoderoso,sistemadetiposestáticoquenosayudaarazonaracercadenuestrocódigo.Comotal,Rustnosproveededostraitsparaayudarnosadarlesentidoacódigoquepuedaposiblementeserconcurrente.

Send

ElprimertraitdelcualhablaremosesSend(ingles).CuandountipoTimplementaSend,leindicaalcompiladorquealgodeestetipopuedetransferirlapertenenciaentrehilosdeformasegura.

Estoesimportanteparahacercumplirciertasrestricciones.Porejemplositenemosuncanal,conectandodoshilos,deberíamosquerertransferiralgunosdatosaelotrohilotravésdelcanal.Porlotanto,nosaseguramosdequeSendhayasidoimplementadoparaesetipo.

Demaneraopuesta,siestamosenvolviendounabibliotecaconFFIquenoesthreadsafe,nodeberíamosquererimplementarSend,demaneratalqueelcompiladornosayudeaasegurarnosqueestanopuedaabandonarelhiloactual.

ElLenguajedeProgramacionRust

111Concurrencia

Page 112: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Sync

ElsegundodeestostraitsesllamadoSync(ingles).CuandountipoTimplementaSync,leindicaalelcompiladorquealgodeestetiponotieneposibilidaddeintroducirinseguridadenmemoriacuandoesusadodemaneraconcurrentepormultipleshilosdeejecución.

Porejemplo,compartirdatainmutableconunacuentadereferenciasatómicaesthreadsafe.Rustproveedichotipo,Arc<T>,elcualimplementaSync,yesporelloqueessegurodecompartirentrehilos.

Estosdostraitstepermitenusarelsistemadetiposparahacergarantíasfuertesacercadelaspropiedadesdetucódigobajoconcurrencia.Enprimerlugar,antesdedemostrarporque,necesitamosaprendercomocrearunprogramaconcurrenteenRust!

HilosLabibliotecaestándardeRustproveeunabibliotecaparaelmanejodehilos,quetepermiteejecutarcódigorustdeformaparalela.Heaquiunejemplobasicodelusodestd::thread:

usestd::thread;

fnmain(){

thread::spawn(||{

println!("Holadesdeunhilo!");

});

}

Elmétodothread::spawn()aceptaunclosurecomoargumento,closurequeesejecutadoenunnuevohilo.thread::spawn()retornaunhandleaelnuevohilo,quepuedeserusadoparaesperaraqueelhilofinaliceyluegoextraersuresultado:

usestd::thread;

fnmain(){

lethandle=thread::spawn(||{

"Holadesdeunhilo!"

});

println!("{}",handle.join().unwrap());

}

ElLenguajedeProgramacionRust

112Concurrencia

Page 113: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Muchoslenguajesposeenlahabilidaddeejecutarhilos,peroessalvajementeinseguro.Existenlibrosenterosacercadecomoprevenirloserroresqueocurrencomoconsecuenciadecompartirestadomutable.Rustayudaconsusistemadetipos,previniendocondicionesdecarreraentiempodecompilación.Hablemosacercadecomoefectivamentepuedescompartircosasentrehilos.

EstadoMutableCompartidoSeguroDebidoaelsistemadetiposdeRust,tenemosunconceptoquesuenacomounamentira:"estadomutablecompartidoseguro".Muchosprogramadoresconcuerdanenqueelestadomutablecompartidoesmuy,muymalo.

Alguiendijoalgunavez:

Elestadomutablecompartidoeslaraízdetodamaldad.Lamayoríadeloslenguajesintentanlidiarconesteproblemaatravésdelaparte'mutable',peroRustloenfrentaresolviendolaparte'compartida'.

Lamismapertenenciaqueprevieneelusoincorrectodeapuntadorestambiénayudaaeliminarlascondicionesdecarrera,unodelospeoresbugsrelacionadosconconcurrencia.

Comoejemplo,unprogramaRustquetendríaunacondicióndecarreraenmuchoslenguajes.EnRustnocompilaría:

usestd::thread;

fnmain(){

letmutdata=vec![1u32,2,3];

foriin0..3{

thread::spawn(move||{

data[i]+=1;

});

}

thread::sleep_ms(50);

}

Loanteriorproduceunerror:

8:17error:captureofmovedvalue:`data`

data[i]+=1;

^~~~

ElLenguajedeProgramacionRust

113Concurrencia

Page 114: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Enestecaso,sabemosquenuestrocódigodeberiaserseguro,peroRustnoestasegurodeello.Enrealidadnoesseguro,situviéramosunareferenciaadataencadahilo,yelhilotomapertenenciadelareferencia,tendríamostresdueños!Esoestamal.PodemosarreglarestoatravésdelusodeltipoArc<T>,unapuntadorconconteoatómicodereferencias.Laparte'atómico'significaqueessegurocompartirloentrehilos.

Arc<T>asumeunapropiedadmasacercadesucontenidoparaasegurarsequeessegurocompartirloentrehilos:asumequesucontenidoesSync.Peroennuestrocaso,queremosmutarelvalor.Necesitamosuntipoquepuedaasegurarsequesolounapersonaalavezpuedamutarloqueestedentro.Paraeso,podemosusareltipoMutex<T>.Heaquílasegundaversiondenuestrocódigo.Aunnofunciona,peroporunarazóndiferente:

usestd::thread;

usestd::sync::Mutex;

fnmain(){

letmutdata=Mutex::new(vec![1u32,2,3]);

foriin0..3{

letdata=data.lock().unwrap();

thread::spawn(move||{

data[i]+=1;

});

}

thread::sleep_ms(50);

}

Heaquielerror:

:9:9:9:22error:thetrait`core::marker::Send`isnotimplementedforthetype`std::sync::mutex::MutexGuard<'_,collections::vec::Vec

:11thread::spawn(move||{

^~~~~~~~~~~~~

:9:9:9:22note:`std::sync::mutex::MutexGuard<'_,collections::vec::Vec>`cannotbesentbetweenthreadssafely

:11thread::spawn(move||{

^~~~~~~~~~~~~

Loves,Mutexposeeunmetodolockqueposeeestafirma:

fnlock(&self)->LockResult>

DebidoaqueSendnoestaimplementadoparaMutexGuard<T>,nopodemostransferirelMutexGuard<T>entrehilos,loquesetraduceenelerror.

PodemosusarArc<T>paracorregirelerror.Heaquilaversionfuncional:

ElLenguajedeProgramacionRust

114Concurrencia

Page 115: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::sync::{Arc,Mutex};

usestd::thread;

fnmain(){

letdata=Arc::new(Mutex::new(vec![1u32,2,3]));

foriin0..3{

letdata=data.clone();

thread::spawn(move||{

letmutdata=data.lock().unwrap();

data[i]+=1;

});

}

thread::sleep_ms(50);

}

Ahorallamamosclone()ennuestroArc,locualincrementaelcontadorinterno.Estehandleesentoncesmovidodentrodelnuevohilo.Examinemoselcuerpodelhilomasdecerca:

#usestd::sync::{Arc,Mutex};

#usestd::thread;

#fnmain(){

#letdata=Arc::new(Mutex::new(vec![1u32,2,3]));

#foriin0..3{

#letdata=data.clone();

thread::spawn(move||{

letmutdata=data.lock().unwrap();

data[i]+=1;

});

#}

#thread::sleep_ms(50);

#}

Primero,llamamoslock(),locualobtieneelbloqueodeexclusionmutua.Debidoaqueestaoperaciónpuedefallar,estemétodoretornaunResult<T,E>,ydebidoaqueestoessolounejemplo,hacemosunwrap()enelparaobtenerunareferenciaaladata.Códigorealtendríaunmanejodeerroresmasrobustoenestelugar.Somoslibresdemutarlo,puestoquetenemoselbloqueo.

Porultimo,mientrasqueloshilosseejecutan,esperamosporlaculminacióndeuntemporizadorcorto.Estonoesideal:pudimoshaberescogidountiemporazonableparaesperarperolomasprobableesqueesperemosmasdelonecesario,onolosuficiente,dependiendodecuantotiempoloshilostomanparaterminarlacomputacióncuandoelprogramacorre.

ElLenguajedeProgramacionRust

115Concurrencia

Page 116: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

UnaalternativamasprecisaaeltemporizadorseriaelusodeunodelosmecanismosproporcionadosporlabibliotecaestándardeRustparalasincronizaciónentrehilos.Hablemosdeellos:loscanales.

CanalesHeaquíunaversionnuestrocódigoqueusacanalesparalasincronización,enlugardeesperarporuntiempoespecifico:

usestd::sync::{Arc,Mutex};

usestd::thread;

usestd::sync::mpsc;

fnmain(){

letdata=Arc::new(Mutex::new(0u32));

let(tx,rx)=mpsc::channel();

for_in0..10{

let(data,tx)=(data.clone(),tx.clone());

thread::spawn(move||{

letmutdata=data.lock().unwrap();

*data+=1;

tx.send(());

});

}

for_in0..10{

rx.recv();

}

}

Hacemosusodelmétodompsc::channel()paraconstruiruncanalnuevo.Enviamos(atravésdesend)unsimple()atravésdelcanal,yluegoesperamosporelregresodiezdeellos.

Mientrasqueestecanalestasoloenviandounasenalgenérica,podemosenviarcualquierdataqueseaSendatravésdelcanal!

ElLenguajedeProgramacionRust

116Concurrencia

Page 117: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::thread;

usestd::sync::mpsc;

fnmain(){

let(tx,rx)=mpsc::channel();

for_in0..10{

lettx=tx.clone();

thread::spawn(move||{

letrespuesta=42u32;

tx.send(respuesta);

});

}

rx.recv().ok().expect("Nosehapodidorecibirlarespuesta");

}

Unu32esSendporquepodemoshacerunacopiadeel.Entoncescreamosunhilo,ylesolicitamosquecalculelarespuesta,esteluegonosenvíalarespuestaderegreso(usandosend())atravésdelcanal.

PanicosUnpanic!causaralafinalizaciónabrupta(crash)delhilodeejecuciónactual.PuedesusarloshilosdeRustcomounmecanismodeaislamientosencillo:

usestd::thread;

letresultado=thread::spawn(move||{

panic!("ups!");

}).join();

assert!(resultado.is_err());

NuestroThreadnosdevuelveunResult,elcualnospermitechequearsielhilohahechopánicoono.

ElLenguajedeProgramacionRust

117Concurrencia

Page 118: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%ManejodeErrores

Losplanesmejorestablecidosporratonesyhombresamenudosetuercen."TaeaMoose",RobertBurns

Algunasveces,lascosassimplementesalenmal.Esimportantetenerunplanparacuandoloinevitablesuceda.Rustposeeunsoportericoparaelmanejodeerroresquepodrían(seamoshonestos:ocurrirán)ocurrirentusprogramas.

Existendostiposdeerroresquepuedenocurrirentusprogramas:fallasypánicos.Hablaremosdelasdiferenciasentrelosdos,yluegodiscutiremoscomomanejarcadauno.Despuésdiscutiremoscomopromoverfallasapánicos.

Fallavs.PánicoRustusadostérminosparadiferenciarentrelasdosformasdeerror:falla,ypánico.Unafallaesunerrordelcualnospodemosrecuperardealgunamanera.Unpánicoesunerrorirrecuperable.

Quequeremosdecircon"recuperar"?Bueno,enlamayoríadeloscasos,laposibilidaddeunerroresesperada.Porejemplo,consideralafunciónparse:

"5".parse();

Estemétodoconvierteunacadenadecaracteresaotrotipo.Perodebidoaqueesunacadenadecaracteres,nosepuedeestarsegurodequelaconversionefectivamentetengaéxito.Porejemplo,aquedeberíaserconvertidoesto?:

"hola5mundo".parse();

Loanteriornofunciona.Sabemosqueelmétodoparse()solotendráéxitoparaalgunasentradas.Esuncomportamientoesperado.Esporelloquellamamosaesteerrorunafalla.

Porotrolado,algunasveces,hayerroresquesoninesperados,odeloscualesnonospodemosrecuperar.Unejemploclásicoesunassert!:

#letx=5;

assert!(x==5);

ElLenguajedeProgramacionRust

118ManejodeErrores

Page 119: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Usamosassert!paradeclararquealgoescierto(true).Siladeclaraciónnoesverdad,entoncesalgoestamuymal.Suficientementemalcomoparanopodercontinuarlaejecuciónenelestadoactual.Otroejemploeselusodelamacrounreachable!():

useEvento::NuevoLanzamiento;

enumEvento{

NuevoLanzamiento,

}

fnprobabilidad(_:&Evento)->f64{

//laimplementaciónrealseriamascompleja,porsupuesto

0.95

}

fnprobabilidad_descriptiva(evento:Evento)->&'staticstr{

matchprobabilidad(&evento){

1.00=>"cierto",

0.00=>"imposible",

0.00...0.25=>"muypocoprobable",

0.25...0.50=>"pocoprobable",

0.50...0.75=>"probable",

0.75...1.00=>"muyprobable",

}

}

fnmain(){

println!("{}",probabilidad_descriptiva(NuevoLanzamiento));

}

Loanteriorresultaraenunerror:

error:non-exhaustivepatterns:`_`notcovered[E0004]

Sibiensabemosquehemoscubiertotodosloscasosposibles,Rustnopuedesaberlo.Nosabecualeslaprobabilidadentre0.0y1.0.Esporelloqueagregamosotrocaso:

ElLenguajedeProgramacionRust

119ManejodeErrores

Page 120: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

useEvento::NuevoLanzamiento;

enumEvento{

NuevoLanzamiento,

}

fnprobabilidad(_:&Evento)->f64{

//laimplementaciónrealseriamascompleja,porsupuesto

0.95

}

fnprobabilidad_descriptiva(evento:Evento)->&'staticstr{

matchprobabilidad(&evento){

1.00=>"cierto",

0.00=>"imposible",

0.00...0.25=>"muypocoprobable",

0.25...0.50=>"pocoprobable",

0.50...0.75=>"probable",

0.75...1.00=>"muyprobable",

_=>unreachable!()

}

}

fnmain(){

println!("{}",probabilidad_descriptiva(NuevoLanzamiento));

}

Nuncadeberíamosalcanzarelcaso_,debidoaestohacemosusodelamacroparaindicarlo.unreachable!()produceuntipodiferentedeerrorqueResult.Rustllamaaesetipodeerrorespánicos.

Manejandoerrorescon Optiony ResultLamaneramassimpledeindicarqueunafunciónpuedefallaresusandoeltipoOption<T>.Porejemplo,elmétodofindenlascadenasdecaracteresintentalocalizarunpatrónenlacadena,retornaunOption:

lets="foo";

assert_eq!(s.find('f'),Some(0));

assert_eq!(s.find('z'),None);

Estoesapropiadoparacasossimples,perononosdamuchainformaciónenelcasodeunafalla.Quetalsiquisiéramossaberelporquelafunciónfalló?Paraello,podemosusareltipoResult<T,E>.Queluceasí:

ElLenguajedeProgramacionRust

120ManejodeErrores

Page 121: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

enumResult<T,E>{

Ok(T),

Err(E)

}

EstaenumesproporcionadaporRust,esporelloquenonecesitasdefinirlasideseashacerusodeella.LavarianteOk(T)representaéxito,ylavarianteErr(E)representaunafalla.RetornarunResultenlugardeunOptionesrecomendableparalamayoríadeloscasosnotriviales:

HeaquíunejemplodelusodeResult:

#[derive(Debug)]

enumVersion{Version1,Version2}

#[derive(Debug)]

enumErrorParseo{LongitudCabeceraInvalida,VersionInvalida}

fnparsear_version(cabecera:&[u8])->Result<Version,ErrorParseo>{

ifcabecera.len()<1{

returnErr(ErrorParseo::LongitudCabeceraInvalida);

}

matchcabecera[0]{

1=>Ok(Version::Version1),

2=>Ok(Version::Version2),

_=>Err(ErrorParseo::LongitudCabeceraInvalida)

}

}

fnmain(){

letversion=parsear_version(&[1,2,3,4]);

matchversion{

Ok(v)=>{

println!("trabajandoconlaversion:{:?}",v);

}

Err(e)=>{

println!("errorparseandocebecera:{:?}",e);

}

}

}

Estafunciónhaceusodeunenum,ErrorParseo,paraenumerarloserroresquepuedenocurrir.

EltraitDebugeselquenospermiteimprimirelvalordelenumusandolaoperacióndeformato{:?}.

ElLenguajedeProgramacionRust

121ManejodeErrores

Page 122: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Erroresnorecuperablescon panic!Enelcasodeunerrorinesperadodelcualnosepuedarecuperar,lamacropanic!seutilizaparainducirunpánico.Dichopánicoterminaraabruptamenteelhiloactualdeejecuciónproporcionandounmensajedeerror:

panic!("boom");

resultaen

thread'

'panickedat'boom',hello.rs:2

cuandoloejecutas.

Debidoaqueestassituacionessonrelativamenteraras,usalospánicosconmoderación.

PromoviendofallasapánicosEnciertascircunstancias,aunsabiendoqueunafunciónpuedefallar,podríamosquerertratarlafallacomounpánico.Porejemplo,io::stdin().read_line(&mutbuffer)retornaunResult<usize>,cuandohayunerrorleyendolalinea.Estonospermitemanejaryposiblementerecuperarnosencasodeerror.

Sinoqueremosmanejarelerror,yensulugarsimplementeabortarelprograma,podemosusarelmétodounwrap():

io::stdin().read_line(&mutbuffer).unwrap();

unwrap()haráunpánico(panic!)sielResultesErr.Estobásicamentedice"Dameelvalor,ysialgosalemal,simplementeabortalaejecución".Estoesmenosconfiablequehacermatchenelerrorytratarderecuperarnos,peroalmismotiempoessignificativamentemascorto.Algunasveces,laterminaciónabruptaesapropiada.

Hayunamaneraquedehacerloanteriorqueesunpocomejorqueunwrap():

letmutbufer=String::new();

letbytes_leidos=io::stdin().read_line(&mutbufer)

.ok()

.expect("Falloalleerlinea");

ElLenguajedeProgramacionRust

122ManejodeErrores

Page 123: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

ok()convierteelResultenunOption,yexpect()hacelomismoqueunwrap(),perorecibeunmensajecomoargumento.Estemensajeespasadoaelpanic!subyacente,proporcionandounmejormensajedeerror.

Usando try!CuandoescribimoscódigoquellamaamuchasfuncionesqueretornaneltipoResult,elmanejodeerroressepuedetornartedioso.Lamacrotry!escondealgodeelcódigorepetitivocorrespondientealapropagacióndeerroresenlapiladellamadas.

try!reemplaza:

usestd::fs::File;

usestd::io;

usestd::io::prelude::*;

structInfo{

nombre:String,

edad:i32,

grado:i32,

}

fnescribir_info(info:&Info)->io::Result<()>{

letmutarchivo=File::create("mis_mejores_amigos.txt").unwrap();

ifletErr(e)=writeln!(&mutarchivo,"nombre:{}",info.nombre){

returnErr(e)

}

ifletErr(e)=writeln!(&mutarchivo,"edad:{}",info.edad){

returnErr(e)

}

ifletErr(e)=writeln!(&mutarchivo,"grado:{}",info.rgrado){

returnErr(e)

}

returnOk(());

}

Con:

ElLenguajedeProgramacionRust

123ManejodeErrores

Page 124: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::fs::File;

usestd::io;

usestd::io::prelude::*;

structInfo{

nombre:String,

edad:i32,

grado:i32,

}

fnescribir_info(info:&Info)->io::Result<()>{

letmutarchivo=File::create("mis_mejores_amigos.txt").unwrap();

try!(writeln!(&mutarchivo,"nombre:{}",info.nombre));

try!(writeln!(&mutarchivo,"edad:{}",info.edad));

try!(writeln!(&mutarchivo,"grado:{}",info.grado));

returnOk(());

}

Envolverunaexpresióncontry!resultaraenelvalor(Ok)exitosodesenvuelto,amenosqueelresultadoseaErr,casoenelcualErresretornadodemaneratempranaporlafunciónqueenvuelvealtry.

Esimportantehacermenciónaelhechodequesolopuedesusartry!desdeunafunciónqueretornaunResult,loquesetraduceenquenopuedesusartry!dentrodemain(),debidoaquemain()noretornanada.

try!haceusodeFrom<Error>(ingles)paradeterminarqueretornarenelcasodeerror.

ElLenguajedeProgramacionRust

124ManejodeErrores

Page 125: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%InterfazdeFuncionesForáneas/Externas

IntroducciónEstaguíausaralabibliotecadecompresión/descompresiónsnappycomointroducciónalaescrituradebindingsacódigoexterno.RustactualmentenopuedellamarcódigoenunabibliotecaC++demaneradirecta,perosnappyincluyeunainterfazenC(documentadaensnappy-c.h).

Elsiguienteesunejemplomininodecomollamarunafunciónforáneaquecompilaraasumiendoquesnappyestainstalada:

##![feature(libc)]

externcratelibc;

uselibc::size_t;

#[link(name="snappy")]

extern{

fnsnappy_max_compressed_length(source_length:size_t)->size_t;

}

fnmain(){

letx=unsafe{snappy_max_compressed_length(100)};

println!("longitudmaximadeunbufferthe100bytescomprimido:{}",x);

}

Elbloqueexternesunalistadefirmasdefunciónenunabibliotecaforánea,enestecasoconlainterfazbinariadeaplicaciónC(ABIeningles)delaplataforma.Elatributo#[link(...)]esusadoparainstruiralenlazadoraenlazarconlabibliotecasnappydemodoquelossímbolospuedanserresueltos.

Seasumequelasinterfacesafuncionesforáneassoninseguras,esporelloquelasllamadasaellasdebenestardentrodeunbloqueunsafe{}comounapromesaalcompiladordequetodolocontenidoenelesrealmenteseguro.BibliotecasenCaalgunasvecesexponeninterfacesquenosonthread-safe,ycasicualquierfunciónquetomaunapuntadorcomoargumentonoesvalidaparatodaslasentradasposiblesdebidoaqueelapuntadorpodríaserunapuntadorcolgante,ylosapuntadoresplanosquedanporfueradelmodelodememoriaseguradeRust.

Cuandosedeclaranlostiposdelosargumentosdeunafunciónforánea,elcompiladordeRustnopuedechequearsiladeclaraciónescorrecta,aconsecuenciadeesto,especificarlademaneracorrectaformapartedemantenerelbindingcorrectoentiempodeejecución.

ElbloqueexternpuedeserextendidoparacubrirlaAPIcompletadesnappy:

ElLenguajedeProgramacionRust

125FFI

Page 126: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

##![feature(libc)]

externcratelibc;

uselibc::{c_int,size_t};

#[link(name="snappy")]

extern{

fnsnappy_compress(input:*constu8,

input_length:size_t,

compressed:*mutu8,

compressed_length:*mutsize_t)->c_int;

fnsnappy_uncompress(compressed:*constu8,

compressed_length:size_t,

uncompressed:*mutu8,

uncompressed_length:*mutsize_t)->c_int;

fnsnappy_max_compressed_length(source_length:size_t)->size_t;

fnsnappy_uncompressed_length(compressed:*constu8,

compressed_length:size_t,

result:*mutsize_t)->c_int;

fnsnappy_validate_compressed_buffer(compressed:*constu8,

compressed_length:size_t)->c_int;

}

#fnmain(){}

CreandounainterfazseguraLainterfazplanaenCnecesitaserenvueltaconelobjetivodeproveerseguridadenelmanejodememoriaasícomoelusodeconceptosdealtoniveltalescomovectores.Unabibliotecapuedeescogerentreexponerlainterfazseguradealtonivelyesconderlosdetallesinsegurosinternos.

Envolverlasfuncionesqueesperanbufersinvolucraelusodeelmoduloslice::rawparalamanipulacióndevectoresRustcomoapuntadoresamemoria.LosvectoresdeRustestángarantizadosaserunbloquedememoriacontiguo.Lalongitudeselnumerodeelementosactualmentecontenidos,ylacapacidadeseltamañototaldelamemoriaasignada.Lalongitudesmenoroigualalacapacidad.

##![feature(libc)]

#externcratelibc;

#uselibc::{c_int,size_t};

#unsafefnsnappy_validate_compressed_buffer(_:*constu8,_:size_t)->c_int{0}

#fnmain(){}

pubfnvalidar_buffer_comprimido(src:&[u8])->bool{

unsafe{

snappy_validate_compressed_buffer(src.as_ptr(),src.len()assize_t)==0

}

}

ElLenguajedeProgramacionRust

126FFI

Page 127: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Lafunciónenvoltoriovalidar_buffer_comprimidohaceusodeunbloqueunsafe,perohacelagarantíadequellamarlaesseguraparatodaslasentradasatravésdelaexclusiondelunsafedelafirmadelafunción.

Lasfuncionessnappy_compressysnappy_uncompresssonmascomplejas,debidoaqueunbufertienequeserasignadoparamantenerlasalida.

Lafunciónsnappy_max_compressed_lengthpuedeserusadaparaasignarunvectorconlacapacidadmaximarequeridaparaalmacenarlasalidacomprimida.Elvectorentoncespuedeserpasadoalafunciónsnappy_compresscomounparámetrodesalida.Unparámetrodesalidaestambiénpasadoparaobtenerlalongitudrealdespuésdelacompresiónparaasignarlalongitud.

##![feature(libc)]

#externcratelibc;

#uselibc::{size_t,c_int};

#unsafefnsnappy_compress(a:*constu8,b:size_t,c:*mutu8,

#d:*mutsize_t)->c_int{0}

#unsafefnsnappy_max_compressed_length(a:size_t)->size_t{a}

#fnmain(){}

pubfncomprimir(orig:&[u8])->Vec<u8>{

unsafe{

letlong_orig=orig.len()assize_t;

letporig=orig.as_ptr();

letmutlong_dest=snappy_max_compressed_length(long_orig);

letmutdest=Vec::with_capacity(long_destasusize);

letpdest=dest.as_mut_ptr();

snappy_compress(porig,long_orig,pdest,&mutlong_dest);

dest.set_len(long_destasusize);

dest

}

}

Ladescompresionessimilar,debidoaquesnappyalmacenalalongituddescomprimidacomopartedelformatodecompresiónysnappy_uncompressed_lengthobtendráeltamañoexactodelbuferrequerido.

ElLenguajedeProgramacionRust

127FFI

Page 128: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

##![feature(libc)]

#externcratelibc;

#uselibc::{size_t,c_int};

#unsafefnsnappy_uncompress(compressed:*constu8,

#compressed_length:size_t,

#uncompressed:*mutu8,

#uncompressed_length:*mutsize_t)->c_int{0}

#unsafefnsnappy_uncompressed_length(compressed:*constu8,

#compressed_length:size_t,

#result:*mutsize_t)->c_int{0}

#fnmain(){}

pubfndescomprimir(orig:&[u8])->Option<Vec<u8>>{

unsafe{

letlong_orig=orig.len()assize_t;

letporig=orig.as_ptr();

letmutlong_dest:size_t=0;

snappy_uncompressed_length(porig,long_orig,&mutlong_dest);

letmutdest=Vec::with_capacity(long_destasusize);

letpdest=dest.as_mut_ptr();

ifsnappy_uncompress(porig,long_orig,pdest,&mutlong_dest)==0{

dest.set_len(long_destasusize);

Some(dest)

}else{

None//SNAPPY_INVALID_INPUT

}

}

}

Comoreferencia,losejemplosusadosaquíestándisponiblestambiéncomounabibliotecaenGithub.

DestructoresLabibliotecasexternasusualmentetransfierenlapertenenciadelosrecursosaelcódigollamador.Cuandoestoocurre,debemosusarlosdestructoresdeRustparaproveerseguridadylagarantíadelaliberacióndedichosrecursos(especialmenteenelcasodeunpánico).

Paramasinformaciónacercadelosdestructores,echaunvistazoalaseccióndeltraitDrop.

CallbacksdesdecódigoCafunciones

ElLenguajedeProgramacionRust

128FFI

Page 129: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

RustAlgunasbibliotecasexternasrequierenelusodecallbacksparareportardevueltasuestadoodataparcialaelllamador.EsposiblepasarfuncionesdefinidasenRustaunabibliotecaexterna.ElrequerimientoparaestoesquelafuncióncallbackestemarcadacomoexternyconlaconvencióndellamadascorrectaparahacerposiblesullamadodesdecódigoC.

LafuncióncallbackpuedeentoncesserenviadaatravésdeunallamadaderegistroalabibliotecaenCysuposteriorinvocacióndesdeallá.

Unejemplobásicoes:

CódigoRust:

externfncallback(a:i32){

println!("HesidollamadodesdeCconelvalor{0}",a);

}

#[link(name="extlib")]

extern{

fnregistrar_callback(cb:externfn(i32))->i32;

fndisparar_callback();

}

fnmain(){

unsafe{

registrar_callback(callback);

disparar_callback();//Disparaelcallback

}

}

CódigoC:

typedefvoid(*callback_rust)(int32_t);

callback_rustcb;

int32_tregistrar_callback(callback_rustcallback){

cb=callback;

return1;

}

voiddisparar_callback(){

cb(7);//Llamaraacallback(7)enRust

}

Enesteejemploelmain()deRustllamaraadisparar_callback()enC,queasuvezllamaradevueltaacallback()enRust.

ElLenguajedeProgramacionRust

129FFI

Page 130: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

ApuntandocallbacksaobjetosRustElejemploanteriordemostrócomounafunciónglobalpuedeserllamadadesdecódigoenC.SiembragoavecessedeseaqueelcallbackapunteaunobjetoRustespecial.EstepodríaserelobjetoquerepresentaelenvoltorioparaelobjetorespectivoenC.

TodoestopuedeserlogradoatravésdelpasodeunapuntadorplanoalabibliotecaenC.LabibliotecaenCentoncespuedeincluirelapuntadoraelobjetoRustenlanotificación.EstopermitiráaelcallbackaccederdemanerainseguraelobjetoRustreferenciado.

CódigoRust:

#[repr(C)]

structObjetoRust{

a:i32,

//otrosmiembros

}

extern"C"fncallback(objetivo:*mutObjetoRust,a:i32){

println!("HesidollamadodesdeCconelvalor{0}",a);

unsafe{

//ActualizaelvalorenObjetoRustconelvalorrecibidodesdeelcallback

(*objetivo).a=a;

}

}

#[link(name="extlib")]

extern{

fnregistrar_callback(objetivo:*mutObjetoRust,

cb:externfn(*mutObjetoRust,i32))->i32;

fndisparar_callback();

}

fnmain(){

//Creandoelobjetoqueserareferenciadoenelcallback

letmutobjeto_rust=Box::new(ObjetoRust{a:5});

unsafe{

registrar_callback(&mut*objeto_rust,callback);

disparar_callback();

}

}

CódigoC:

ElLenguajedeProgramacionRust

130FFI

Page 131: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

typedefvoid(*callback_rust)(void*,int32_t);

void*objetivo_cb;

callback_rustcb;

int32_tregistrar_callback(void*objetivo_callback,callback_rustcallback){

objetivo_cb=objetivo_callback;

cb=callback;

return1;

}

voiddisparar_callback(){

cb(objetivo_cb,7);//Llamareacallback(&ObjetoRust,7)inRust

}

CallbacksAsíncronosEnlosejemplosanterioresloscallbackssoninvocadoscomounareaccióndirectaaunallamadaafunciónalabibliotecaexternaenC.ElcontrolsobreelhiloactualescambiadodeRustaCparalaejecucióndelcallback,peroalfinalelcallbackesejecutadoenelmismohiloquellamoalafunciónquedisparoelcallback.

Lascosassevuelvenmascomplicadascuandolabibliotecaexternacreasuspropioshiloseinvocaloscallbacksdesdeellos.EnestoscasoselaccesoalasestructurasdedatosRustdentrodeloscallbacksesespecialmenteinseguroymecanismosdesincronizaciónapropiadosdebenserusados.Ademasdelosmecanismosclásicosdesincronizacióncomomutexes,unaposibilidadenRusteselusodecanales(enstd::sync::mpsc)paratransferirdatadesdeelhiloCqueinvocoelcallbackaunhiloRust.

SiuncallbackasíncronotienecomoobjetivounobjetoespecialenelespaciodedireccionesdeRustesabsolutamentenecesariotambiénqueningúnotrocallbackseaejecutadosporlabibliotecaenCdespuésdequeelrespectivoobjetoRusthayasidodestruido.Estopuedeserllevadoacabode-registrandoelcallbackeneldestructordelobjetoydiseñandolabibliotecademaneratalquegaranticequeningúncallbackseraejecutadodespuésdelade-registracion.

EnlaceElatributolinkenbloquesexternproporcionaelbloquedeconstrucciónbasicoparainstruirarustccomoenlazarconbibliotecasnativas.Hoyendiahaydosformasdelatributolink:

#[link(name="foo")]

ElLenguajedeProgramacionRust

131FFI

Page 132: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#[link(name="foo",kind="bar")]

Enamboscasos,fooeselnombredelabibliotecanativaconlacualestamosenlazando,yenelsegundocasobareseltipodebibliotecanativaalacualestaenlazandoelcompilador.Actualmentehaytrestiposdebibliotecasnativasconocidos:

Dinamicas-#[link(name="readline")]Estaticas-#[link(name="my_build_dependency",kind="static")]Frameworks-#[link(name="CoreFoundation",kind="framework")]

NotaquelosframeworkssoloestándisponiblesenobjetivosOSX.

Losdiferentesvaloreskindtienencomoobjetodiferenciarcomolabibliotecanativaparticipaenelenlace.Desdelaperspectivadelenlace,elcompiladordeRustcreadostiposdeartefactos:parciales(rlib/staticlib)yfinales(dylib/binary).Lasdependenciasenbibliotecasnativasyframeworkssonpropagadasalafronteradeartefactofinal,mientrasquelasdependenciasestáticasnosonpropagadasdeltodo,debidoaquelasbibliotecasestáticasestánintegradasdirectamentedentrodelartefactosubsecuente.

Unospocosejemplosdecomoestemodelopuedeserusadoson:

Unadependenciadeconstrucciónnativa:AlgunasvecesalgúnC/C++depegamentoesnecesariocuandoseescribeuntipoespecificodecódigoRust,peroladistribucióndelcódigoenunformatodebibliotecaessimplementeunacarga.Enestecaso,elcódigoseraarchivadoenunlibfoo.ayluegoelcraterustdeclararaunadependenciavia#[link(name="foo",kind="static")].

Independientementedeltipodesalidaparaelcrate,labibliotecanativaestáticaseraincluidaenlasalida,significandoqueladistribucióndelabibliotecaestáticanativanoesnecesaria.

Unadependenciadinámicanormal:Bibliotecascomunesdelsistema(comoreadline)estándisponiblesenungrannumerodesistemas,yamenudounacopiaestáticadeesasbibliotecapuedenoexistir.CuandoestadependenciaesincluidaenuncrateRust,objetivosparciales(comorlibs)noenlazaranalabiblioteca,perocuandoelrlibesincluidoenunobjetivofinal(comounbinario),labibliotecaseraenlazada.

EnOSX,losframeworkssecomportanconlamismasemanticaqueunabibliotecadinámica.

BloquesUnsafe

ElLenguajedeProgramacionRust

132FFI

Page 133: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Algunasoperaciones,comodereferenciarpunterosplanosollamadasafuncionesquehansidomarcadascomoinsegurassolosonpermitidasdentrodebloquesunsafe.Losbloquesunsafeaíslanlainseguridadysonunapromesaalcompiladorquelainseguridadnosefiltrarahaciaelexteriordelbloque.

Lasfuncionesunsafe,porotrolado,hacenpublicidaddelainseguridadaelmundoexterior.Unafuncióninseguraseescribedelasiguientemanera:

unsafefnkaboom(ptr:*consti32)->i32{*ptr}

Estafunciónpuedeserinvocadasolodesdeunbloqueunsafeuotrafunciónunsafe.

AccediendoglobalesexternasAPIsforáneasalgunasvecesexportanunavariableglobalquepodríahaceralgocomollevarregistrodealgunestadoglobal.Conlafinalidaddeaccederdichasvariables,debesdeclararlasenbloquesexternconlapalabrareservadastatic:

##![feature(libc)]

externcratelibc;

#[link(name="readline")]

extern{

staticrl_readline_version:libc::c_int;

}

fnmain(){

println!("Tieneslaversion{}dereadline.",

rl_readline_versionasi32);

}

Alternativamente,podríasnecesitaralterarestadoglobalproporcionadoporunainterfazforánea.Parahaceresto,losestáticospuedenserdeclaradosconmutconlafinalidaddepodermutarlos.

ElLenguajedeProgramacionRust

133FFI

Page 134: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

##![feature(libc)]

externcratelibc;

usestd::ffi::CString;

usestd::ptr;

#[link(name="readline")]

extern{

staticmutrl_prompt:*constlibc::c_char;

}

fnmain(){

letprompt=CString::new("[my-awesome-shell]$").unwrap();

unsafe{

rl_prompt=prompt.as_ptr();

println!("{:?}",rl_prompt);

rl_prompt=ptr::null();

}

}

Notaquetodalainteracciónconunstaticmutesinsegura,amboslecturayescritura.Lidiarconestadoglobalmutablerequieredeungrancuidado.

ConvencionesdellamadasforáneasLamayoríadeelcódigoforáneoexponeunABIC,yRustusapordefectolaconvencióndellamadasdelaplataformaalmomentodellamarfuncionesexternas.Algunasfuncionesforáneas,notablementeelAPIdeWindows,usanotraconvenióndellamadas.Rustproveeunaformadeinformaralcompiladoracercadecualconvencióndebeserusada:

##![feature(libc)]

externcratelibc;

#[cfg(all(target_os="win32",target_arch="x86"))]

#[link(name="kernel32")]

#[allow(non_snake_case)]

extern"stdcall"{

fnSetEnvironmentVariableA(n:*constu8,v:*constu8)->libc::c_int;

}

#fnmain(){}

Estoaplicaaelbloqueexterncompleto.LalistaderestriccionesABIsoportadasson:

stdcall

ElLenguajedeProgramacionRust

134FFI

Page 135: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

aapcs

cdecl

fastcall

Rust

rust-intrinsic

system

C

win64

Lamayoríadelasabissonauto-explicativas,peroelabisystempuedeparecerunpocoraro.EstarestricciónseleccionacualquieraqueseaelABIapropiadoparainteroperarconlasbibliotecasobjetivo.Porejemplo,enwin32conunaarquitecturax86,significaqueelabiusadoserastdcall.Enx86_64,sinembargo,WindowsusalaconvencióndellamadasC,entoncesseusaC.Estosetraduceaqueennuestroejemploanterior,pudimoshaberhechousodeextern"system"{...}paradefinirunbloqueparatodoslossistemasWindows,nosololosx86.

InteroperabilidadconcódigoexternoRustgarantizaqueladistribucióndeunstructseacompatibleconlarepresentacióndelaplataformaenCsolosielatributo#[repr(C)]esaplicado.#[repr(C,packed)]puedeserusadoparadistribuirlosmiembrossinpadding.#[repr(C)]puedeseraplicadotambiénaunenum.

LosboxesRust(Box<T>)usanapuntadoresno-nulablescomohandlesqueapuntanaelobjetocontenido.Sinembargo,nodebensercreadosmanualmentedebidoquesonmanejadosporasignadoresinternos.Lareferenciaspuedenserasumidasdemaneraseguracomoapuntadoresno-nulablesdirectosaltipo.Sinembargo,romperelchequeodepréstamo(borrowing)olasreglasdemutabilidadnosegarantizaserseguro,esporelloqueseprefiereelusodeapuntadoresplanos(*)desernecesariodebidoaqueelcompiladornopuedeasumirmuchascosasacercadeellos.

Losvectoresylascadenasdecaracterescompartenlamismadistribuciónenmemoria,yutilidadesparainteractuarconAPIsCestándisponiblesenlosmódulosvecystr.Sinembargo,lascadenasdecaracteresnosonterminadasen\0.SinecesitasunacadenadecaracteresquetermineenNULparainteractuarconC,debesentonceshacerusodeeltipoCStringenelmodulostd::ffi.

LabibliotecaestándarincluyealiasdetipoydefinicionesdefuncionesparalabibliotecaestándardeCenelmodulolibc,yRustenlazapordefectoconlibcylibm.

ElLenguajedeProgramacionRust

135FFI

Page 136: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

La"optimizaciondeapuntadornulable"Ciertostiposestándefinidosparanosernull.Estoincluyereferencias(&T,&mutT),boxes(Box<T>),yapuntadoresafunciones(extern"abi"fn()).CuandohacesinterfazconC,apuntadoresquepuedensernullsonusadosalgunasveces.Comouncasoespecial,unenumgenéricoquecontieneexactamentedosvariantes,delascualesunanocontienedataylaotracontieneunsolocampo,eselegibleparala"optimizaciondeapuntadornulable".Cuandodichaenumesinstanciadaconunodelostiposno-nulables,esrepresentadacomounsoloapuntador,ylavariantesindataesrepresentadacomoelapuntadornull.EntoncesOption<extern"C"fn(c_int)->c_int>escomounorepresentaunapuntadorafunciónnullableusandoelABIdeC.

LlamandocodingRustdesdeCPodríasquerercompilarcódigoRustdemodoquepermitaserllamadodesdeC.Estoesfácil,perorequiereciertascosas:

#[no_mangle]

pubexternfnhola_rust()->*constu8{

"Hola,mundo!\0".as_ptr()

}

#fnmain(){}

ElexternhacequeestafunciónseadhieraalaconvencióndellamadasdeC,talycomosediscuteen"Convencionesdellamadasforáneas".Elatributono_mangledesactivaelestropeo(mangling)denombresdeRust,demaneratalqueseamasfacildeenlazar.

FFIypánicosEsimportanteestarconscientedelospanic!oscuandosetrabajaconFFI.Unpanic!enallimitedeFFIescomportamientoindefinido.Siestasescribiendocódigoquepuedahacerpánico,debesejecutarloenotrohilo,deestaformaelpániconosepropagarahastaC:

ElLenguajedeProgramacionRust

136FFI

Page 137: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::thread;

#[no_mangle]

pubexternfnoh_no()->i32{

leth=thread::spawn(||{

panic!("Oops!");

});

matchh.join(){

Ok(_)=>1,

Err(_)=>0,

}

}

#fnmain(){}

ElLenguajedeProgramacionRust

137FFI

Page 138: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%BorrowyAsRef

LosttraitsBorrowandAsRefsonmuysimilares,perodiferentes.Heaquíunbreverepasoacercadeloquesignificandichostraits:

BorrowEltraitBorrowseusacuandoestamosescribiendounestructuradedatos,ydeseamosusaruntipoownedountipoborrowedcomosinónimoporalgunarazón.

Porejemplo,HashMapposeeunmetodogetqueusaBorrow:

fnget(&self,k:&Q)->Option<&V>

whereK:Borrow“,

Q:Hash+Eq

Estafirmaescomplicada.ElparametroKesenloqueestamosinteresadosahora.SerefiereaunparametrodelHashMapensimismo:

structHashMap{

ElparametroKeseltipodelaclavequeusaelHashMap.Alverdenuevolafirmadeget(),solopodemosusarget()cuandolaclaveimplementaBorrow<Q>.Deestamanera,podemoscrearunHashMapqueuseclavesStringperoalmomentodebuscaruse&strs:

usestd::collections::HashMap;

letmutmap=HashMap::new();

map.insert("Foo".to_string(),42);

assert_eq!(map.get("Foo"),Some(&42));

EstoesdebidoaquelabibliotecaestándarposeeunaimplBorrow<str>forString.

Paralamayoríadelostipos,cuandodeseestomaruntipoyaseaownedoborrowed,un&Tessuficiente.PerounareaenlacualBorrowesefectivoescuandohaymasdeuntipodevalorborrowed.Estoesespecialmenteciertoenreferenciasyslices:puedestenerambosun&Tun&mutT.SiqueremosaceptarambostiposBorrowesloquenecesitamos:

ElLenguajedeProgramacionRust

138BorrowyAsRef

Page 139: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::borrow::Borrow;

usestd::fmt::Display;

fnfoo<T:Borrow<i32>+Display>(a:T){

println!("aesunborrowed:{}",a);

}

letmuti=5;

foo(&i);

foo(&muti);

Thiswillprintoutaesunborrowed:5dosveces.

AsRefEltraitAsRefesuntraitdeconversion.Esusadoparaconvertiralgúnvaloraunareferenciaencódigogenerico.Comoesto:

lets="Hola".to_string();

fnfoo<T:AsRef<str>>(s:T){

letslice=s.as_ref();

}

Cualdeberíausar?Podemosvercomoambossonunaespeciedelomismo:amboslidianconlasversionesownedyborroweddealgúntipo.Sinembargo,sondiferentes.

EscogeBorrowcuandoquierasabstraerteporencimadediferentestiposdeborrowing,ocuandoestasconstruyendounaestructuradedatosquetratalosvaloresownedyborroweddeformasequivalentes,comoelhashingylacomparación.

UsaAsRefcuandodeseesconvertiralgodirectamenteenunareferencia,yestésescribiendocódigogenérico.

ElLenguajedeProgramacionRust

139BorrowyAsRef

Page 140: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%CanalesdeDistribución

ElproyectoRustusaunconceptodenominado‘canalesdedistribución’paraadministrarlosreleases.

EsimportanteentenderesteprocesoparaasípoderdecidircualversiondeRustdebeusartuproyecto.

VisióngeneralHaytrescanalesparalosreleasesdeRust:

Nocturno(nightly)BetaEstable(stable)

Losreleasesnocturnossoncreadosunavezaldía.Cadaseissemanas,elultimoreleasenocturnoespromovidoa'Beta'.Enestepunto,solorecibiráparchesquearreglenerroresserios.Seissemanasdespuéselbetaespromovidoa'Estable',yseconvierteenelnuevoreleasede1.x.

Esteprocesoocurreenparalelo.Cadaseissemanas,enelmismodíaelnocturnosubeabeta,elbetaespromovidoaestable.Cuando1.xesliberado,almismotiempo,1.(x+1)-betaesliberado,yelnocturnosevuelvelaprimeraversionde1.(x+2)-nightly.

EscogiendounaversiónGeneralmentehablando,amenosquetengasunarazónespecifica,deberíasusarelcanaldedistribuciónestable.Esosreleasestienencomoobjetivounaaudienciageneral.

Sinembargo,dependiendodetuinterésenRust,podríasescogerelnocturno.Elbalanceeselsiguiente:enelcanalnocturno,puedeshacerusodenuevascaracterísticasdeRust.Sinembargo,lascaracterísticasinestablesestánsujetasalcambio,yesporelloquecualquiernocturnotienelaposibilidadderompertucódigo.Siusaselreleaseestable,notienesaccesoacaracterísticasexperimentales,peroelsiguientereleasedeRustnocausaraproblemassignificativosacausadecambios.

AyudandoaelecosistemaatravesdeCI

ElLenguajedeProgramacionRust

140CanalesdeDistribución

Page 141: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Quehayacercadebeta?NosotrosrecomendamosatodoslosusuariosRustqueusanelcanaldedistribuciónestableaquetambiénpruebenensussistemasdeintegracióncontinuaconelcanalbeta.Estoayudaraaadvertiralequipoencasodequeexistaunaregresiónaccidental.

Adicionalmente,probarcontraelnocturnopuededetectarregresionesmuchomastemprano,esporelloquesinoteimportateneruntercerbuild,apreciamosquepruebescontratodosloscanales.

ElLenguajedeProgramacionRust

141CanalesdeDistribución

Page 142: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%SintaxisySemántica

EstaseccióndivideaRustenpequeñospedazos,unoparacadaconcepto.

SideseasaprenderRustdeabajohaciaarriba,leerestasecciónenordenesunamuybuenaformadehacerlo.

Estasseccionesformanunareferenciaparacadaconcepto,siestasleyendootrotutorialyencuentrasalgoconfuso,puedesencontrarloexplicadoenalgúnlugardeestasección.

ElLenguajedeProgramacionRust

142SintaxisySemantica

Page 143: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%EnlacesaVariable

Virtualmentecualquierprogramano-'HolaMundo’usaenlacesavariables.Dichosenlacesavariableslucenasí:

fnmain(){

letx=5;

}

Colocarfnmain(){encadaejemploesunpocotedioso,asíqueenelfuturoloomitiremos.Siestassiguiendopasoapaso,aseguratedeeditartufunciónmain(),enlugardedejarlaporfuera.Deotromodoobtendrásunerror.

Enmuchoslenguajes,estoesllamadounavariable,perolosenlacesavariabledeRusttienenunpardetrucosbajolamanga.Porejemploelladoizquierdodeunaexpresiónletesun‘patron’,nounsimplenombredevariable.Estosetraduceenquepodemoshacercosascomo:

let(x,y)=(1,2);

Despuésdequeestaexpresiónesevaluada,xserauno,yyserados.Lospatronessonrealmentepoderosos,ytienensupropiasecciónenellibro.Nonecesitamosesasfacilidadesporahora,solomantengamosestoennuestrasmentesmientrasavanzamos.

Rustesunlenguajeestáticamentetipificado,loquesignificaqueespecificamosnuestrostiposporadelantado,yestossonchequeadosentiempodecompilación.Entonces,porquenuestroprimerejemplocompila?Bueno,Rusttieneestacosallamada‘inferenciadetipos’.Sipuededeterminareltipodealgo,Rustnorequierequeescribaseltipo.

Podemosagregareltiposilodeseamos.Lostiposvienendespuésdedospuntos(:):

letx:i32=5;

Sitepidieraleerestoenvozaltaalrestodelaclase,dirías“xesunenlaceconeltipoi32yelvalorcinco.”

Enestecasodecidimosrepresentarxcomounenteroconsignode32bits.Rustposeemuchostiposdeenterosprimitivosdiferentes.Estoscomienzanconiparalosenterosconsignoyconuparalosenterossinsigno.Lostamañosposiblesparaenterosson8,16,32,y64bits.

Enejemplosfuturos,podríamosanotareltipoenuncomentario.Elejemploluciríaasí:

ElLenguajedeProgramacionRust

143EnlacesaVariables

Page 144: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnmain(){

letx=5;//x:i32

}

Notalassimilitudesentrelaanotaciónylasintaxisqueusasconlet.IncluirestaclasedecomentariosnoesidiomáticoenRust,perolosincluiremosocasionalmenteparaayudarteaentendercualessonlostiposqueRustinfiere.

Pordefecto,losenlacessoninmutables.Estecódigonocompilara:

letx=5;

x=10;

Daracomoresultadoelsiguienteerror:

error:re-assignmentofimmutablevariable`x`

x=10;

^~~~~~~

Sideseasqueunenlaceavariableseamutable,puedeshacerusodemut:

letmutx=5;//mutx:i32

x=10;

Nohayunarazónúnicaporlacuallosenlacesavariablesoninmutablespordefecto,peropodemospensaracercadeelloatravésdeunodelosfocosprincipalesdeRust:seguridad.Siolvidasdecirmut.elcompiladorlonotará,yteharásaberquehasmutadoalgoquenoteniasintencióndemutar.Silosenlacesavariablesfuesenmutablespordefecto,elcompiladornoseriacapazdedecirteesto.Siteniaslaintencióndemutaralgo,entonceslasoluciónesmuyfácil:agregarmut.

Hayotrasbuenasrazonesparaevitarestadomutablesiemprequeseaposible,peroestanfueradelalcancedeestaguisa.Engeneral,puedesfrecuentementeevitarmutaciónexplicita,yestoespreferibleenRust.Dichoesto,algunasveces,lamutaciónesjustoloquenecesitas,esporelloquenoestaprohibida.

Volvamosalosenlacesavariables.LosenlacesavariableenRustposeenunaspectomasquedifieredeotroslenguajes:serequiereesteninicializadosaunvalorantesquepuedasusarlos.

Pongamosestoaprueba.Cambiatuarchivosrc/main.rsparaqueluzcaasí:

ElLenguajedeProgramacionRust

144EnlacesaVariables

Page 145: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnmain(){

letx:i32;

println!("Hola,mundo!");

}

Puedesusarcargobuildenlalineadecomandoparacompilarlo.Obtendrásunaadvertenciaperoaunasíimprimirá"Hola,mundo!":

Compilinghola_mundov0.0.1(file:///home/tu/proyectos/hola_mundo)

src/main.rs:2:9:2:10warning:unusedvariable:`x`,#[warn(unused_variable)]

onbydefault

src/main.rs:2letx:i32;

^

Rustnosadviertequenuncahacemosusodelenlaceavariable,perodebidoaquenuncalausamos,nohaypeligro,nohayfalta.Sinembargo,lascosascambiansiefectivamenteintentamosusarx.Hagamoseso.Cambiatuprogramaparaqueluzcadelasiguientemanera:

fnmain(){

letx:i32;

println!("Elvalordexes:{}",x);

}

Intentacompilarlo.Obtendrásunerror:

$cargobuild

Compilinghola_mundov0.0.1(file:///home/tu/proyectos/hola_mundo)

src/main.rs:4:39:4:40error:useofpossiblyuninitializedvariable:`x`

src/main.rs:4println!("Elvalordexes:{}",x);

^

note:inexpansionofformat_args!

<stdmacros>:2:23:2:77note:expansionsite

<stdmacros>:1:1:3:2note:inexpansionofprintln!

src/main.rs:4:5:4:42note:expansionsite

error:abortingduetopreviouserror

Couldnotcompile`hello_world`.

Rustnotepermitiráusarunvalorquenohayasidoinicializadopreviamente.Acontinuaciónhablemosdeloquelehemosagregadoaprintln!.

ElLenguajedeProgramacionRust

145EnlacesaVariables

Page 146: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Siincluyesunpardellaves({},algunaspersonaslosllamanbigotes/moustaches...)enlacadenadecaracteresaimprimir,Rustlointerpretaracomounapeticiónparainterpolaralgunaclasedevalor.Lainterpolaciónencadenasdecaracteresesunterminoencienciasdelacomputaciónquesignifica"colocaestodentrodelacadenadecaracteres".Agregamosunacoma,yluegox,paraindicarquequeremosqueesteseaelvalorinterpolado.Lacomaesusadaparasepararlosargumentosquepasamosalasfuncionesylosmacros,enelcasodepasarmasdeuno.

Cuandousaslasllaves,Rustintentarámostrarelvalordeunaformaquetengasentidodespuésdechequearsutipo.Sideseamosespecificarunformatomasdetallado,existenunamplionumerodeopcionesdisponible.Porahora,nosapegaremosalcomportamientopordefecto:losnúmerosenterosnosonmuycomplicadosdeimprimir.

ElLenguajedeProgramacionRust

146EnlacesaVariables

Page 147: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Funciones

TodoprogramaRustposeealmenosunafunción,lafunciónmain:

fnmain(){

}

Estaesladeclaracióndefunciónmassimpleposible.Comohemosmencionadoanteriormente,fndice‘estoesunafunción’,seguidodelnombre,paréntesisdebidoaqueestafunciónnorecibeningúnargumento,yluegollavesparaindicarelcuerpodelafunción.Heaquíunafunciónllamadafoo:

fnfoo(){

}

Entonces,quehayacercaderecibirargumentos?Acontinuaciónunafunciónqueimprimeunnumero:

fnimprimir_numero(x:i32){

println!("xes:{}",x);

}

Acáunprogramacompletoquehaceusodeimprimir_numero:

fnmain(){

imprimir_numero(5);

}

fnimprimir_numero(x:i32){

println!("xes:{}",x);

}

Comopodrásver,losargumentosdefuncióntrabajandemaneramuysimilaralasdeclaracioneslet:agregasuntipoaelnombredelargumento,despuésdedospuntos.

Heaquíunprogramacompletoquesumadosnúmerosyluegolosimprime:

fnmain(){

imprimir_suma(5,6);

}

fnimprimir_suma(x:i32,y:i32){

println!("lasumaes:{}",x+y);

}

ElLenguajedeProgramacionRust

147Funciones

Page 148: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Losargumentossonseparadosporunacoma,enamboscasos,cuandollamasalafunciónasícomocuandoladeclaras.

Adiferenciadelet,debesdeclararlostiposdelosargumentos.Losiguiente,nocompilara:

fnimprimir_suma(x,y){

println!("sumaes:{}",x+y);

}

Obtendríaselsiguienteerror:

expectedoneof`!`,`:`,or`@`,found`)`

fnimprimir_suma(x,y){

Estoesunadeliberadadecisióndediseño.Aunquelainferenciadelprogramacompletoespossible,loslenguajesquelaposeen,comoHaskell,amenudosugierenquedocumentartustiposdemaneraexplicitaesunabuenapractica.Nosotroscoincidimosenqueobligaralasfuncionesadeclararlostiposalmismotiempopermitiendoinferenciadentrodelafunciónesunmaravillosopuntomedioentreinferenciacompletaylaausenciadeinferencia.

Quehayacercaderetornarunvalor?Acontinuaciónunafunciónquesumaunoaunentero:

fnsuma_uno(x:i32)->i32{

x+1

}

LafuncionesenRustretornanexactamenteunvalor,yeltipoesdeclaradodespuésdeuna‘flecha’,queesunguión(-)seguidoporunsignomayor-que(>).Laultimalineadeunafuncióndeterminaloqueestaretorna.Notaraslaausenciadeunpuntoycomaaquí.Deagregarlo:

fnsuma_uno(x:i32)->i32{

x+1;

}

Obtendríamosunerror:

ElLenguajedeProgramacionRust

148Funciones

Page 149: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

error:notallcontrolpathsreturnavalue

fnsuma_uno(x:i32)->i32{

x+1;

}

help:considerremovingthissemicolon:

x+1;

^

LoanteriorreveladoscosasinteresantesacercadeRust:esunlenguajebasadoenexpresiones,ylospuntosycomasondiferentesalosdeotroslenguajesbasadosen‘llavesypuntosycoma’.Estasdoscosasestánrelacionadas.

Expresionesvs.SentenciasRustenunlenguajeprincipalmentebasadoenexpresiones.Existensolodostiposdesentencias,todolodemásesunaexpresión.

Entonces,cualesladiferencia?Lasexpresionesretornanunvalor,ylassentenciasno.Esporelloqueterminamosconelerror‘notallcontrolpathsreturnavalue’aquí:lasentenciax+1;noretornaningúnvalor.HaydostiposdesentenciasenRust:‘sentenciasdedeclaración’and‘sentenciasdeexpresión’.Todolodemásesunaexpresión.Hablemosprimerodelassentenciasdedeclaración.

Enalgunoslenguajes,losenlacesavariablepuedenserescritoscomoexpresiones,nosolosentencias.ComoenRuby:

x=y=5

EnRust,sinembargo,elusodeletparaintroducirunenlaceavariablenoesunaexpresión.Losiguienteproduciráunerrorentiempodecompilación:

letx=(lety=5);//expectedidentifier,foundkeyword`let`

Elcompiladornosdicequeestabaesperandoelcomienzodeunaexpresión,yunletpuedesersolounasentencia,nounaexpresión.

Notaquelaasignaciónaunavariablequehasidopreviamenteasignada(e.j.y=5)esunaexpresión,aunasísuvalornoesparticularmenteutil.Adiferenciadeotroslenguajesenlosqueunaasignaciónesevaluadaaelvalorasignado(e.j.5enejemploanterior),enRustelvalordeunaasignaciónesunatuplavacía()debidoaqueelvalorasignadopuedetenerunsolodueñoycualquierotrovalorderetornoseriasorpresivo:

ElLenguajedeProgramacionRust

149Funciones

Page 150: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

letmuty=5;

letx=(y=6);//xposeeelvalor`()`,no`6`

ElsegundotipodesentenciaenRusteslasentenciadeexpresión.Supropósitoesconvertircualquierexpresiónenunasentencia.Entérminosprácticos,lagramáticadeRustesperaqueunasentenciaseaseguidapormassentencias.Estosignificaquepuedesusarpuntosycomaparasepararunaexpresióndeotra.EstocausaqueRustluzcamuysimilaraesoslenguajesenloscualesserequiereunpuntoycomaalfinaldecadalinea,dehecho,observaraspuntosycomaalfinaldecasitodaslaslineasdeRustqueveras.

Entonces,Cualeslaexcepciónquenoshacedecir"casi"?Yalohasvistoenelcódigoanterior:

fnsuma_uno(x:i32)->i32{

x+1

}

Nuestrafunciónclamaretornaruni32,peroconunpuntoycoma,retornaría().Rustdeterminaqueestonoesprobablementeloquequeremos,ysugierelaremocióndelpuntoycomaenelerrorquevimosanteriormente.

RetornostempranosPeroquehayacercadelosretornostempranos?Rustproporcionaunapalabrareservadaparaello,return:

fnfoo(x:i32)->i32{

returnx;

//nuncaalcanzaremosestecódigo!

x+1

}

Usarunreturncomolaultimalineadeunafunciónesvalido,peroesconsideradopobreestilo:

fnfoo(x:i32)->i32{

returnx+1;

}

ElLenguajedeProgramacionRust

150Funciones

Page 151: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Ladefiniciónpreviasinelreturnpuedelucirunpocoextrañasinuncahastrabajadoconunlenguajebasadoenexpresiones,peroestasevuelveintuitivaconeltiempo.

FuncionesdivergentesRusttieneunasintaxisespecialparalas‘funcionesdivergentes’,quesonfuncionesquenoretornan:

fndiverge()->!{

panic!("Estafunciónnuncaretorna!");

}

panic!esunamacro,similaralaprintln!()queyahemosvisto.Adiferenciadeprintln!(),panic!()causaqueelhilodeejecuciónactualterminedemaneraabruptamostrandoelmensajeproporcionado.

Debidoaqueestafuncióncausaraunasalidaabrupta,estanuncaretornara,esporelloqueposeeeltipo‘!’,queselee‘diverge’.Unafuncióndivergentepuedeserusadacomocualquiertipo:

#fndiverge()->!{

#panic!("Estafunciónnuncaretorna!");

#}

letx:i32=diverge();

letx:String=diverge();

ApuntadoresafunciónTambiénpodemoscrearenlacesavariablesqueapuntenafunciones:

letf:fn(i32)->i32;

fesunenlaceavariablequeapuntaaunafunciónquetomauni32comoargumentoyretornauni32.Porejemplo:

ElLenguajedeProgramacionRust

151Funciones

Page 152: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnmas_uno(i:i32)->i32{

i+1

}

//sininferenciadetipos

letf:fn(i32)->i32=mas_uno;

//inferenciadetipos

letf=mas_uno;

Podemosentonceshacerusodefparallamaralafunción:

#fnmas_uno(i:i32)->i32{i+1}

#letf=mas_uno;

letseis=f(5);

ElLenguajedeProgramacionRust

152Funciones

Page 153: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%TiposPrimitivos

Rustposeeunconjuntodetiposquesonconsiderados‘primitivos’.Estosignificaqueestánintegradosenellenguaje.Rustestaestructuradodetalmaneraquelabibliotecaestándartambiénproveeunanumerodetiposútilesbasadosenlosprimitivos,peroestossonlosmasprimitivos.

BooleanosRustposeeuntipobooleanointegrado,denominadobool.Tienedosposiblesvalorestrueyfalse:

letx=true;

lety:bool=false;

Unusocomúndelosbooleanosesencondicionalesif.

Puedesencontrarmasdocumentaciónparalosbooleanosenladocumentacióndelabibliotecaestándar(ingles).

char

EltipocharrepresentaununicovalorescalarUnicode.Puedescrearcharsconcomillassimples:(')

letx='x';

letdos_corazones='';

Adiferenciadeotroslenguajes,estosignificaquecharenRustnoesunsolobyte,sinocuatro.

Puedesencontrarmasdocumentaciónparaloscharsenladocumentacióndelabibliotecaestándar(ingles).

TiposnuméricosRustposeeunavariedaddetiposnuméricosenunaspocascategorías:consignoysinsigno,fijosyvariables,depuntoflotanteyenteros.

ElLenguajedeProgramacionRust

153TiposPrimitivos

Page 154: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Dichostiposconsistendedospartes:lacategoría,yeltamaño.Porejemplo,u16esuntiposinsignoconuntamañodedieciséisbits.Masbitstepermitenalmacenarnúmerosmasgrandes.

Siunliteraldenumeronoposeenadaquecauselainferenciadesutipo,seusantipospordefecto:

letx=42;//xtieneeltipoi32

lety=1.0;//ytieneeltipof64

Heaquíunalistadelosdiferentestiposnuméricos,conenlacesasudocumentaciónenlabibliotecaestándar(ingles):

i8i16i32i64u8u16u32u64isizeusizef32f64

Veamoscadaunadelasdiferentescategorías.

ConsignoysinsignoLostiposdeenterosvienenendosvariedades:consignoysinsigno.Paraentenderladiferencia,consideremosunnumeroconcuatrobitsdetamaño.Unnumerodecuatrobitsconsignotepermitiríaalmacenarlosnúmerosdesde-8a+7.Losnúmerosconsignousanla“representacióndelcomplementoados”.Unnumerodecuatrosbitssinsigno,debidoaquenonecesitaguardarlosvaloresnegativos,puedealmacenarvaloresdesde0hasta+15.

Lostipossinsignousanunauparasucategoria,ylostiposconsignousani.Laiesdeinteger(entero).Entonces,u8esunnumerodeochobitssinsigno,yuni8esunnumerodeochobitsconsigno.

ElLenguajedeProgramacionRust

154TiposPrimitivos

Page 155: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

TiposdetamañofijoLostiposdetamañofijoposeenunnumeroespecificodebitsensurepresentación.Lostamañosvalidosson8,16,32,and64.Entoncesu32esunenterosinsignode32bits,ei64esunenteroconsignode64bits.

TiposdetamañovariableRusttambiénproveetiposparaloscualeseltamañodependedeltamañodelapuntadorenlamaquinasubyacente.Dichostiposposeenlacategoría‘size’,yvienenenvariantesconysinsigno.Estoresultaendostiposisizeyusize.

TiposdepuntoflotanteRusttambiénposeedostiposdepuntoflotante:f32yf64.EstoscorrespondenalosnúmerosIEEE-754desimpleydobleprecision.

ArreglosComomuchoslenguajesdeprogramación,Rustposeetiposlistapararepresentarunasecuenciadecosas.Elmasbásicoeselarreglo,unalistadeelementosdelmismotipoydetamañofijo.Pordefectolosarreglossoninmutables.

leta=[1,2,3];//a:[i32;3]

letmutm=[1,2,3];//m:[i32;3]

Losarreglostieneneltipo[T;N].HablaremosdelanotaciónTenlaseccióndegenéricos.LaNesunaconstanteentiempodecompilación,paralalongituddelarreglo.

Hayunatajoparalainicializacióndecadaunodeloselementosdelarregloaelmismovalor.Enesteejemplo,cadaelementodeaserainicializadoa0:

leta=[0;20];//a:[i32;20]

Puedesobtenerelnumerodeelementosdelarregloacona.len()

ElLenguajedeProgramacionRust

155TiposPrimitivos

Page 156: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

leta=[1,2,3];

println!("atiene{}elementos",a.len());

Puedesaccederunelementodelarregloenparticularconlanotacióndesubindices:

letnombres=["Graydon","Brian","Niko"];//names:[&str;3]

println!("Elsegundonombrees:{}",nombres[1]);

Lossubindicescomienzanencero,comoenlamayoríadeloslenguajesdeprogramación,entonceselprimernombreesnombres[0]yessegundoesnombres[1].Elejemploanteriorimprime:Elsegundonombrees:Brian.Siintentasusarunsubíndicequenoestaenelarreglo,obtendrásunerror:elchequeodeloslimitesenelaccesoalarregloserealizaentiempodeejecución.Elaccesoerrantecomoeseeslafuentedemuchosbugsenloslenguajesdeprogramacióndesistemas.

Puedesencontrarmasdocumentaciónparalosarraysenladocumentacióndelabibliotecaestándar(ingles).

SlicesUnsliceesunareferenciaa(ouna“vista”dentrode)otraestructuradedatos.Losslicessonútilesparapermitiraccesoseguroyeficienteaunaporcióndeunarreglosininvolucrarelcopiado.Porejemplo,podríasquererhacerreferenciaaunasolalineadeunaarchivoquehasidopreviamenteleídoenmemoria.Pornaturaleza,unslicenoescreadodirectamente,estossoncreadosparaunavariablequeyaexiste.Losslicesposeenunalongitud,puedensermutablesoinmutables,yenmuchasformassecomportancomolosarreglos:

leta=[0,1,2,3,4];

letmiddle=&a[1..4];//Unslicedea:sololoselementos1,2,y3

letcomplete=&a[..];//Unsliceconteniendotodosloselementosdea.

Losslicesposeeneltipo&[T].HablaremosacercadeTcuandocubramoslosgenericos.

Puedesencontrarmasdocumentaciónparalosslicesenladocumentacióndelabibliotecaestándar(ingles)

str

ElLenguajedeProgramacionRust

156TiposPrimitivos

Page 157: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

ElstrdeRusteseltipodecadenadecaracteresmasprimitivo.Comountiposintamaño,ynoesmuyutilensimismo,perosevuelvemuyutilcuandoespuestodetrásdeunareferencia,como&str.Esporelloquelodejaremoshastaaquí.

Puedesencontrarmasdocumentaciónparastrenladocumentacióndelabibliotecaestándar(ingles)

TuplasUnatuplaesunalistaordenadadetamañofijo.Comoesto:

letx=(1,"hola");

Losparéntesisycomasformanestatupladelongituddos.Heaquíelmismocódigoperoconanotacionesdetipo:

letx:(i32,&str)=(1,"hola");

Comopuedesver,eltipodeunatuplaesjustocomolatupla,peroconcadaposiciónteniendoeltipoenlugardelvalor.Loslectorescuidadosostambiénnotaranquelastuplassonheterogéneas:tenemosuni32ya&strenestatupla.Enloslenguajesdeprogramacióndesistemas,lascadenasdecaracteressonunpocomascomplejasqueenotroslenguajes.Porahorasololee&strcomounslicedecadenadecaracteres.Aprenderemosmasdentrodepoco.

Puedesasignarunatuplaaotra,siestastienenlosmismotiposcontenidosylamismaaridad.Latuplesposeenlamismaaridadcuandoestastienenelmismotamaño.

letmutx=(1,2);//x:(i32,i32)

lety=(2,3);//y:(i32,i32)

x=y;

Puedesaccederaloscamposdeunatuplaatravésdeunletcondestructuracion.Heaquíunejemplo:

let(x,y,z)=(1,2,3);

println!("xes{}",x);

ElLenguajedeProgramacionRust

157TiposPrimitivos

Page 158: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Recuerdasanteriormentecuandodijequeelladoizquierdodeunasentencialeteramaspoderosoquelasimpleasignacióndeunbinding?Henosaquí.Podemoscolocarunpatronenelladoizquierdodeunlet,ysiesteconcuerdaconelladoderecho,podemosasignarmultiplesbindingsavariabledeunasolavez.Enestecaso,ellet“destructura”o“parte”latupla,yasignalaspartesalostresbindingsavariable.

Estepatronesmuypoderoso,yloveremosrepetidoconfrecuenciaenelfuturo.

Puedeseliminarlaambigüedadentreunatupladeunsoloelementoyunvalorencerradoenparéntesisusandounacoma:

(0,);//tupladeunsoloelemento

(0);//ceroencerradoenparentesis

IndexadoentuplasPuedestambiénaccederloscamposdeunatuplaconlasintaxisdeindexado:

lettupla=(1,2,3);

letx=tupla.0;

lety=tupla.1;

letz=tupla.2;

println!("xes{}",x);

Aligualqueelindexadoenarreglos,estecomienzaencero,peroadiferenciadeelindexadoenarreglos,seusan.,enlugarde[]s.

Puedesencontrarmasdocumentaciónparatuplasenladocumentacióndelabibliotecaestándar(ingles)

FuncionesLasfuncionestambiéntienenuntipo!Estaslucenasí:

fnfoo(x:i32)->i32{x}

letx:fn(i32)->i32=foo;

Enestecaso,xesun‘apuntador’aunafunciónquerecibeuni32yretornauni32.

ElLenguajedeProgramacionRust

158TiposPrimitivos

Page 159: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Comentarios

Ahoraquehemosvistosalgunasfunciones,esbuenaideaaprendersobreloscomentarios.Loscomentariossonnotasquedejasaotrosprogramadoresconlafinalidaddeexplicaralgúnaspectodetucódigo.Elcompiladormayormente,losignora.

Rustposeedostiposdecomentariosquetedebeninteresar:comentariosdelineaycomentariosdededocumentación

//Loscomentariosdelineasoncualquiercosadespuésde‘//’yseextiendenhastaelfinaldelalinea

letx=5;//esteestambiénuncomentariodelinea

//Sitienesunalargaexplicaciónacercadealgo,puedescolocarcomentarios

//delineaunosjuntos.Ponunespacioentretus//ytucomentarioconel

//findehacerlosmaslegibles.

Elotrotipodecomentarioesuncomentariodedocumentación(ocomentariodoc).Loscomentariosdocusan///enlugarde//,ysoportannotaciónMarkdownensuinterior:

///Sumaunoalnumeroproporcionado

///

///#Examples

///

///

///letcinco=5;//////assert_eq!(6,suma_uno(5));///#fnsuma_uno(x:i32)->i32{///#x+1///#}///```fnsuma_uno(x:i32)->i32{x+1}

Existeotroestilodecomentarios,`//!`,conlafinalidaddecomentarlositemscontenedores(e.jcrates,modulosofunciones),enlugardelositemsquelossiguen.Sonusadoscomúnmenteenlaraizdeuncrate(lib.rb)oenlaraizdeunmodulo(mod.rs):

//!#LaBibliotecaEstándardeRust//!//!LaBibliotecaEstándardeRustproporcionalafuncionalidad//!entiempodeejecuciónesencialparalaconstruccióndesoftware//!Rustportable.```

Cuandoseescribencomentariosdoc,proporcionaralgunosejemplosdeusoesmuy,muyutil.Notarasquehemoshechousodeunamacro:assert_eq!.Estacomparadosvalores,yhacepanic!osiestosnosoniguales.Esmuyutilenladocumentación.Tambiénexisteotramacro,assert!,lacualhacepanic!osielvalorproporcionadoesfalse.

PuedesusarlaherramientarustdocparagenerardocumentaciónenHTMLapartirdedichoscomentarios,asícomoejecutarelcódigodelosejemploscomopruebas!

ElLenguajedeProgramacionRust

159Comentarios

Page 160: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%if

ElenfoquedeRustconrelaciónaifnoesparticularmentecomplejo,peroesmassimilaraelifqueencontrarasenlenguajescontipificadodinámicoquealdeloslenguajesdesistemastradicionales.Hablemosunpocoacercadeeste,paraestarsegurosdequeentiendastodoslosmatices.

ifesunaformaespecificadeaunconceptomasgeneral,el‘branch’(rama).Elnombreprovienedeunaramaenunárbol:esunpuntodedecisión,enelcualdependiendodeunaopción,multiplescaminospuedensertomados.

Enelcasodeif,hayunasolaelecciónqueconduceadoscaminos:

letx=5;

ifx==5{

println!("xescinco!");

}

Dehabercambiadoelvalordexaalgodiferente,estalineanohubiesesidoimpresa.Parasermasespecifico,silaexpresióndespuésdelifesevaluadaatrue,entonceselbloquedecódigoesejecutado.Siesfalse,dichobloquenoseinvoca.

Sideseasquealgoocurraenelcasodefalse,debeshacerusodeunelse:

letx=5;

ifx==5{

println!("xescinco!");

}else{

println!("xnoescinco:(");

}

Dehabermasdeuncaso,usaunelseif:

letx=5;

ifx==5{

println!("xescinco!");

}elseifx==6{

println!("xesseis!");

}else{

println!("xnoesnicinconiseis:(");

}

Todoestoesbienestándar.Sinembargo,tambiénpuedeshaceresto:

ElLenguajedeProgramacionRust

160if

Page 161: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

letx=5;

lety=ifx==5{

10

}else{

15

};//y:i32

Locualpodemos(yprobablementedeberiamos)escribirasí:

letx=5;

lety=ifx==5{10}else{15};//y:i32

Estofuncionaporqueifesunaexpresión.Elvalordelaexpresióneselvalordelaultimaexpresiónenelbloquequehayasidoseleccionado.Unifsinunelsesiempreresultaen()comovalor.

ElLenguajedeProgramacionRust

161if

Page 162: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Ciclos

Rustactualmenteproveetresenfoquespararealizaractividaditerativa.loop,whileyfor.Cadaunodedichosenfoquestienesuspropiosusos.

loopElcicloinfinitoloopeselciclomassimpledisponibleenRust.Atravesdelusodelapalabrareservadaloop,Rustproporcionaunaformadeiterarindefinidamentehastaquealgunasentenciadeterminaciónseaalcanzada.ElloopinfinitodeRustluceasí:

loop{

println!("Iteraporsiempre!");

}

whileRusttambiéntieneunciclowhile.Lucedeestamanera:

letmutx=5;//mutx:i32

letmutcompletado=false;//mutcompletado:bool

while!completado{

x+=x-3;

println!("{}",x);

ifx%5==0{

completado=true;

}

}

Loscicloswhilesonlaeleccióncorrectacuandonoestasseguroacercadecuantasvecesnecesitasiterar.

Denecesitaruncicloinfinito,podríassentirtetentadoaescribiralgocomoesto:

whiletrue{

Sinembargo,loopesporlejos,elmejorparaestecaso:

loop{

ElLenguajedeProgramacionRust

162Ciclos

Page 163: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

ElanálisisdeflujodecontroldeRusttrataestaconstruccióndemaneradiferentequeaunwhiletrue,debidoaquesabemosqueiteraremosporsiempre.Engeneral,mientrasmasinformaciónleproporcionemosalcompilador,estepodríadesempeñarsemejorenrelaciónalaseguridadygeneracióndecódigo,esporelloquesiempredeberíaspreferirloopcuandotengasplaneadoiterardemaneraindefinida.

forElcicloforesusadoparaiterarunnumeroparticulardeveces.LosciclosfordeRust,sinembargo,trabajandemaneradiferentealosdeotroslenguajesdeprogramacióndesistemas.ElfordeRustnolucecomoestecicloforal“estiloC”

for(x=0;x<10;x++){

printf("%d\n",x);

}

Ensulugar,elciclofordeRustluceasí:

forxin0..10{

println!("{}",x);//x:i32

}

Entérminosligeramentemasabstractos:

forvarinexpresion{

código

}

Laexpresiónesuniterador.Eliteradorretornaunaseriedeelementos.Cadaelementoesunaiteracióndelciclo.Esevaloresasuvezasignadoaelnombrevar,elcualesvalidoenelcuerpodelciclo.Unavezqueelciclohaterminado,elsiguientevaloresobtenidodeliterador,yseiteraunavezmas.Cuandonohaymasvalores,elciclofortermina.

Ennuestroejemplo,0..10esunaexpresiónquetomaunaposicióndeinicioyunadefin,ydevuelveuniteradorporsobreesosvalores.Ellimitesuperioresexclusivo,entonces,nuestroloopimprimiráde0hasta9,no10.

RutnoposeeelcicloforalestilodeC,aproposito.Controlarmanualmentecadaelementodelcicloescomplicadoypropensoaerrores,inclusoparaprogramadoresCexperimentados.

ElLenguajedeProgramacionRust

163Ciclos

Page 164: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Enumerate

Cuandonecesitasllevarregistrodecuantasveceshasiterado,puedesusarlafunción.enumerate().

Enrangos:

for(i,j)in(5..10).enumerate(){

println!("i={}yj={}",i,j);

}

Salida:

i=0yj=5

i=1yj=6

i=2yj=7

i=3yj=8

i=4yj=9

Noolvidescolocarlosparéntesisalrededordelrango.

Eniteradores:

#letlineas="hola\nmundo".lines();

for(numero_linea,linea)inlineas.enumerate(){

println!("{}:{}",numero_linea,linea);

}

Outputs:

0:Contenidodelalineauno

1:Contenidodelalineados

2:Contenidodelalineatres

3:Contenidodelalineacuatro

FinalizandolaiteracióndemaneratempranaEchemosunvistazoaeseciclowhilequevimosconanterioridad:

ElLenguajedeProgramacionRust

164Ciclos

Page 165: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

letmutx=5;

letmutcompletado=false;

while!completado{

x+=x-3;

println!("{}",x);

ifx%5==0{

completado=true;

}

}

Necesitamosmantenerunbindingavariablemut,completado,parasabercuandodebíamossalirdelciclo.Rustposeedospalabrasclaveparaayudarnosamodificarelprocesodeiteración:breakycontinue.

Enestecaso,podemosescribirelciclodeunamejorformaconbreak:

letmutx=5;

loop{

x+=x-3;

println!("{}",x);

ifx%5==0{break;}

}

Ahoraiteramosdemaneraindefinidaconloopyusamosbreakpararomperelciclodemaneratemprana.Usarunreturnexplícitotambiénsirveparalaterminacióntempranadelciclo.

continueessimilar,peroenlugardeterminarelciclo,noshaceiralasiguienteiteración.Losiguienteimprimirálosnumerosimpares:

forxin0..10{

ifx%2==0{continue;}

println!("{}",x);

}

Etiquetasloop

ElLenguajedeProgramacionRust

165Ciclos

Page 166: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Tambiénpodríasencontrarsituacionesenlascualestengasciclosanidadosynecesitesespecificaracualdelosciclospertenecentussentenciasbreakocontinue.Comoenlamayoríadeloslenguajes,pordefectounbreakocontinueaplicaaelciclomasinterno.Enelcasodequedesearasaplicarunbreakocontinueparaalgunodelosciclosexternos,puedesusaretiquetasparaespecificaracualcicloaplicalasentenciabreakocontinue.Losiguientesoloimprimirácuandoambosxyyseanimpares:

'exterior:forxin0..10{

'interior:foryin0..10{

ifx%2==0{continue'exterior;}//continuaelcicloporencimadex

ify%2==0{continue'interior;}//continuaelcicloporencimadey

println!("x:{},y:{}",x,y);

}

}

ElLenguajedeProgramacionRust

166Ciclos

Page 167: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Pertenencia

EstaguíaesunadelastrespresentandoelsistemadepertenenciadeRust.EsteesunadelascaracterísticasmasúnicaseirresistiblesdeRust,conlaquedesarrolladoresRustdebenestarfamiliarizados.AtravésdelapertenenciaescomoRustlograsuobjetivomasimportante,laseguridad.Existenunospocosconceptosdistintos,cadaunoconsupropiocapitulo:

pertenencia,laqueleesactualmentepréstamo,ysucaracterísticaasociada‘referencias’tiempodevida,unconceptoavanzadodelpréstamo

Estostrescapítulosestánrelacionados,enorden.NecesitaraslostresparaentendercompletamenteelsistemadepertenenciadeRust.

MetaAntesdeentrarendetalle,dosnotasimportantesacercadelsistemadepertenencia.

Rusttienefocoenseguridadyvelocidad.Rustlograesosobjetivosatravezdemuchas‘abstraccionesdecerocosto’,loquesignificaqueenRust,lasabstraccionescuestantanpococomoseaposibleparahacerlasfuncionar.Elsistemadepertenenciaesunejemploprimordialdeunaabstraccióndecerocosto.Todoelanálisisdelqueestaremoshablandoenlapresenteguíaesllevadoacaboentiempodecompilación.Nopagasningúncostoentiempodeejecuciónporningunadeestasfacilidades.

Sinembargo,estesistematieneciertocosto:lacurvadeaprendizaje.MuchosusuariosnuevosRustexperimentanalgoquenosotrosdenominamos‘pelearconelcomprobadordepréstamo’(‘fightingwiththeborrowchecker’),situaciónenlacualelcompiladordeRustserehusaacompilarunprogramaelcualelautorpiensavalido.EstoocurreconfrecuenciadebidoaqueelmodelomentaldelprogramadoracercadecomofuncionalapertenencianoconcuerdaconlasreglasactualesimplementadasenRust.Probablementetuexperimentescosassimilaresalcomienzo.Sinembargo,haybuenasnoticias:otrosdesarrolladoresRustexperimentadosreportanqueunavezquetrabajanconlasreglasdelsistemadepertenenciaporunperiododetiempo,peleancadavezmenosconelcomprobadordepréstamo.

Conesoenmente,aprendamosacercadelapertenencia.

Pertenencia

ElLenguajedeProgramacionRust

167Pertenencia

Page 168: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

LosBindingsavariableposeenunapropiedadenRust:Estos‘poseenpertenencia’sobreloqueestánasociados.Loquesetraduceaquecuandounbindingavariablesaledeámbito,Rustliberalosrecursosasociadosaeste.Porejemplo:

fnfoo(){

letv=vec![1,2,3];

}

Cuandoventraenámbito,unnuevoVec<T>escreado.Enestecasoelvectortambiénasignaalgodememoriadesdeelmontículo,paralostreselementos.Cuandovsaledeámbitoalfinaldefoo(),Rustlimpiaratodolorelacionadoalvector,incluyendolamemoriaasignadadesdeelmontículo.Estoocurredemaneradeterminista,alfinaldeelámbito.

SemanticademovimientoHayalgomassutilacá,Rustseaseguraquesoloexistaexactamenteunbindingacualquierrecursoenparticular.Porejemplo,sitenemosunvector,podemosasignarloaotrobindingavariable:

letv=vec![1,2,3];

letv2=v;

Pero,siintentamosusarvdespués,obtenemosunerror:

letv=vec![1,2,3];

letv2=v;

println!("v[0]es:{}",v[0]);

Elerrorlucecomoeste:

error:useofmovedvalue:`v`(usodevalormovido:`v`)

println!("v[0]es:{}",v[0]);

^

Algosimilarocurresidefinimosunafunciónquetomepertenencia,ytratamosdeusaralgodespuésdehabérselopasadocomoargumento:

ElLenguajedeProgramacionRust

168Pertenencia

Page 169: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fntomar(v:Vec){

//loquesucedeacánoesrelevante

}

letv=vec![1,2,3];

tomar(v);

println!("v[0]es:{}",v[0]);

Elmismoerror:‘useofmovedvalue’(usodevalormovido).Cuandotransferimoslapertenenciaaalgo,decimosquehemos‘movido’lacosaalacualnosestamosrefiriendo.Nonecesitasningúntipodeanotaciónespecialparaello,esloqueRusthacepordefecto.

LosdetallesLarazónporlacualnopodemosusarunbindingavariabledespuésdehaberlomovidoessutil,peroimportante.Cuandoescribimoscódigocomoeste:

letv=vec![1,2,3];

letv2=v;

Laprimeralineaasignamemoriaparaelobjetovector,v,yparaladataquecontiene.Elobjetovectoresentoncesalmacenadoenlapilapilaycontieneunapuntadoraelcontenido([1,2,3])almacenadoenelmonticulo.Cuandomovemosvav2,secreaunacopiadedichoapuntadorparav2.Todoestosignificaqueexistiríandosapuntadoresparaelcontenidodelvectorenelmontículo.LocualviolalasgarantíasdeseguridaddeRust,introduciendounacondicióndecarrera.EsporelloqueRustprohibeelusodevdespuésqueelmovimientohasidollevadoacabo.

Esimportantedestacarquealgunasoptimizacionespodríanremoverlacopiadelosbytesenlapila,dependiendodeciertascircunstancias.Asíquepuedenosertanineficienteacomoluceinicialmente.

TiposCopyHemosestablecidoquecuandotransferimoslapertenenciaaotrobindingavariable,nopodemosusarelbindingoriginal.Sinembargo,existeuntraittraitquecambiaestecomportamiento,sellamaCopy.Nohemosdiscutidolostraits(rasgos)todavía,peropor

ElLenguajedeProgramacionRust

169Pertenencia

Page 170: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

ahorapuedesverloscomounaanotaciónhechaauntipoenparticularlacualagregacomportamientoextra.Porejemplo:

letv=1;

letv2=v;

println!("ves:{}",v);

Enestecaso,vesuni32,queimplementaeltraitCopy.Estosignificaque,justocomoenunmovimiento,cuandoasignamosvav2,unacopiadeladataeshecha.Pero,adiferenciadeloqueocurreenunmovimiento,podemoshacerusodevdespués.Estoesdebidoaqueuni32noposeeapuntadoresadataenningúnotrolugar,copiarlossignificacopiadocompleto.

TodoslostiposprimitivosimplementaneltraitCopyysupertenencianoesmovidacomounopodríaasumir,siguiendolasreglasdepertenencia.Comoejemplo,lossiguientesdospedazosdecódigosolocompilanporquelostiposi32yboolimplementaneltraitCopy.

fnmain(){

leta=5;

let_y=doblar(a);

println!("{}",a);

}

fndoblar(x:i32)->i32{

x*2

}

fnmain(){

leta=true;

let_y=cambiar_verdad(a);

println!("{}",a);

}

fncambiar_verdad(x:bool)->bool{

!x

}

DehabertenidotiposquenoimplementaseneltraitCopy,hubiésemosobtenidounerrordecompilaciónportratardeusarunvalormovido.

ElLenguajedeProgramacionRust

170Pertenencia

Page 171: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

error:useofmovedvalue:`a`

println!("{}",a);

^

DiscutiremoscomohacerquetuspropiostiposseanCopyenlaseccióndetraits

MasquepertenenciaPorsupuesto,sinecesitaremosdevolverlapertenenciaconcadafunciónqueescribiésemos:

fnfoo(v:Vec<i32>)->Vec<i32>{

//haceralgoconv

//devolviendopertenencia

v

}

Lascosassevolveríanbastantetediosas.Seponeaunpeormientrastengamosmascosassobrelascualesqueramostenerpertenencia:

fnfoo(v1:Vec<i32>,v2:Vec<i32>)->(Vec<i32>,Vec<i32>,i32){

//haceralgoconv1yv2

//devolviendopertenencia,asícomoelresultadodenuestrafunción

(v1,v2,42)

}

letv1=vec![1,2,3];

letv2=vec![1,2,3];

let(v1,v2,respuesta)=foo(v1,v2);

Ugh!Eltipoderetorno,lalineaderetorno,yelllamadoalafunciónsevuelvenmuchomascomplicados.

Porsuerte,Rustofreceunafacilidad,elpréstamo,facilidadquenossirveparasolucionaresteproblema.

Eseltópicodelasiguientesección!

ElLenguajedeProgramacionRust

171Pertenencia

Page 172: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%ReferenciasyPréstamo

EstaguíaesunadelastrespresentandoelsistemadepertenenciadeRust.EstaesunadelascaracterísticasmasúnicasyatractivasdeRust,conlaquelosdesarrolladoresRustdebenestarbienfamiliarizados.LapertenenciaescomoRustlograsuobjetivomayor,seguridadenelmanejodememoria.Existenunospocosconceptosdistintos,cadaunoconsupropiocapitulo:

pertenencia,elconceptoprincipalprestamo,elqueleesahoratiemposdevida,unconceptoavanzadodelpréstamo

Estostrescapítulosestánrelacionados,yenorden.Necesitarasleerlostresparaentendercompletamenteelsistemadepertenencia.

MetaAntesdeentrarendetalle,dosnotasimportantesacercadelsistemadepertenencia.

Rusttienefocoenseguridadyvelocidad.Rustlograesosobjetivosatravezdemuchas‘abstraccionesdecerocosto’,loquesignificaqueenRust,lasabstraccionescuestantanpococomoseaposibleparahacerlasfuncionar.Elsistemadepertenenciaesunejemploprimordialdeunaabstraccióndecerocosto.Todoelanálisisdelqueestaremoshablandoenlapresenteguíaesllevadoacaboentiempodecompilación.Nopagasningúncostoentiempodeejecuciónporningunadeestasfacilidades.

Sinembargo,estesistematieneciertocosto:lacurvadeaprendizaje.MuchosusuariosnuevosRustexperimentanalgoquenosotrosdenominamos‘pelearconelcomprobadordepréstamo’(‘fightingwiththeborrowchecker’),situaciónenlacualelcompiladordeRustserehusaacompilarunprogramaelcualelautorpiensavalido.EstoocurreconfrecuenciadebidoaqueelmodelomentaldelprogramadoracercadecomofuncionalapertenencianoconcuerdaconlasreglasactualesimplementadasenRust.Probablementetuexperimentescosassimilaresalcomienzo.Sinembargo,haybuenasnoticias:otrosdesarrolladoresRustexperimentadosreportanqueunavezquetrabajanconlasreglasdelsistemadepertenenciaporunperiododetiempo,peleancadavezmenosconelcomprobadordepréstamo.

Conesoenmente,aprendamosacercadeelpréstamo.

Préstamo

ElLenguajedeProgramacionRust

172ReferenciasyPréstamo

Page 173: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Alfinaldelaseccióndepertenencia,teníamosunafunciónfeaqueluciaasí:

fnfoo(v1:Vec<i32>,v2:Vec<i32>)->(Vec<i32>,Vec<i32>,i32){

//haceralgoconv1yv2

//devolviendopertenencia,asícomoelresultadodenuestrafunción

(v1,v2,42)

}

letv1=vec![1,2,3];

letv2=vec![1,2,3];

let(v1,v2,respuesta)=foo(v1,v2);

Loanterior,sinembargo,noesRustidiomatico,debidoaquenosebeneficiadelasventajasdelpréstamo.Heaquielprimerpaso:

fnfoo(v1:&Vec<i32>,v2:&Vec<i32>)->i32{

//haceralgoconv1yv2

//retornandolarespuesta

42

}

letv1=vec![1,2,3];

letv2=vec![1,2,3];

letrespuesta=foo(&v1,&v2);

//podemosusarav1yv2aqui

EnlugardetomarVec<i32>scomoargumentos,tomamosunareferencia:&Vec<i32>.Yenlugardepasarv1yv2directamente,pasamos&v1y&v2.Llamamosaltipo&Tuna'referencia',yenvezdetomarpertenenciasobreelrecurso,estelatomaprestado.Unenlaceavariablequehaceunpréstamodealgonoliberaelrecursocuandosaledeámbito.Estosignificaquedespuésdelallamadaafoo(),podemosnuevamentehacerusodelosenlacesavariableoriginales.

Lasreferenciassoninmutables,justocomolosenlacesavariable.Estosetraduceaquedentrodefoo(),losvectoresnopuedensercambiados:

ElLenguajedeProgramacionRust

173ReferenciasyPréstamo

Page 174: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnfoo(v:&Vec){

v.push(5);

}

letv=vec![];

foo(&v);

fallacon:

error:cannotborrowimmutableborrowedcontent`*v`asmutable

v.push(5);

^

Insertarunvalorcausaunamutaciónenelvector,ynotenemospermitidohacerlo.

referencias&mutExisteunsegundotipodereferencia:&mutT.Una‘referenciamutable’quepermitemutarelrecursoqueestastomandoprestado.Porejemplo:

letmutx=5;

{

lety=&mutx;

*y+=1;

}

println!("{}",x);

Loanteriorimprimirá6.Hacemosayunareferenciamutableax,entoncessumamosunoaloqueseaqueyapunta.Notarasquextambiéntuvoquehabersidomarcadocomomut,delocontrario,nohubiésemospodidotomarunpréstamomutableaunvalorinmutable.

Notarastambiénquehemosagregadounasterisco(*)alfrentedey,tornándoloen*y,estoesdebidoaqueyesunareferencia&mut.Tambiénnecesitarashacerusodeellosparaaccederaelcontenidodeunareferencia.

Deotromodo,lasreferencias&mutsoncomolasreferencias.Existeunagrandiferenciaentrelasdos,ycomoestasinteractuan.Habrásnotadoqueexistealgoquenohuelemuybienenelejemploanterior,puestoquenecesitamoseseámbitoextra,conlos{y}.Silosremovemos,obtenemosunerror:

ElLenguajedeProgramacionRust

174ReferenciasyPréstamo

Page 175: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

error:cannotborrow`x`asimmutablebecauseitisalsoborrowedasmutable

println!("{}",x);

^

note:previousborrowof`x`occurshere;themutableborrowprevents

subsequentmoves,borrows,ormodificationof`x`untiltheborrowends

lety=&mutx;

^

note:previousborrowendshere

fnmain(){

}

^

Alparecer,hayreglas.

LasReglasHeaquilasreglasacercadelpréstamoenRust:

Primero,cualquierpréstamodebevivirenunámbitonomayoraldeeldueño.Segundo,puedestenerunouotrodeestostiposdepréstamo,peronolosdosalmismotiempo:

unaomasreferencias(&T)aunrecurso,exactamenteunareferenciamutable(&mutT).

Posiblementenotesqueestoesmuysimilar,peronoexactamenteigual,aladefinicióndeunacondicióndecarrera:

Hayuna‘condicióndecarrera’cuandodosomasapuntadoresaccedenalamismalocaciónenmemoriaalmismotiempo,endondealmenosunoestaescribiendo,ylasoperacionesnoestánsincronizadas.

Conlasreferencias,puedestenercuantasdesees,debidoaqueningunadeellasestaescribiendo.Siestasescribiendo,ynecesitasdosomasapuntadoresalamismamemoria,puedestenersoloun&mutalavez.EsasícomoRustprevienelascondicionesdecarreraentiempodecompilación:obtendremoserroressirompemoslasreglas.

Conestoenmente,consideremosnuestroejemplootravez.

PensandoenámbitosHeaquielcódigo:

ElLenguajedeProgramacionRust

175ReferenciasyPréstamo

Page 176: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

letmutx=5;

lety=&mutx;

*y+=1;

println!("{}",x);

Elcódigoanteriorgeneraelsiguienteerror:

error:cannotborrow`x`asimmutablebecauseitisalsoborrowedasmutable

println!("{}",x);

^

Estoesdebidoaquehemosvioladolasreglas:tenemosun&mutTapuntandoax,yenconsecuencianotenemospermitidocrearningún&Ts.Unacosauotra.Lanotaapuntaacomopensaracercadeesteproblema:

note:previousborrowendshere

fnmain(){

}

^

Enotraspalabras,elpréstamomutableesmantenidoalolargodeelrestodenuestroejemplo.Loquequeremosesquenuestropréstamomutabletermineantesqueintentemosllamaraprintln!yhagamosunpréstamoinmutable.EnRust,elpréstamoestaasociadoalámbitoenelcualelpréstamoesvalido.Nuestrosámbitoslucenasí:

letmutx=5;

lety=&mutx;//-+préstamo&mutdexcomienzaaqui

//|

*y+=1;//|

//|

println!("{}",x);//-+-intentodetomarprestadoxaqui

//-+préstamo&mutdexterminaaqui

Losámbitosentranenconflicto:nopodemoscrearun&xmientrasyestaenámbito.

Entoncescuandoagregamosllaves:

ElLenguajedeProgramacionRust

176ReferenciasyPréstamo

Page 177: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

letmutx=5;

{

lety=&mutx;//-+préstamo&mutdexcomienzaaqui

*y+=1;//|

}//-+...yterminaaqui

println!("{}",x);//<-intentodetomarprestadoxaqui

Nohayproblema.Nuestropréstamomutablesaledeámbitoantesdequecreemosunpréstamoinmutable.Elámbitoesclaveparavercuantoduraelpréstamo.

ProblemasqueelpréstamoprevienePorquetenemosestasreglasrestrictivas?Bueno,comolonotamos,estasreglasprevienencondicionesdecarrera.Quetiposdeproblemascausanlascondicionesdecarrera?Acáunospocos.

InvalidacióndeIteradores

Unejemploesla‘invalidacióndeiteradores’,queocurrecuandotratasdemutarunacolecciónmientrasestasiterandosobreella.ElcomprobadordeprestamosdeRustevitaqueestoocurra:

letmutv=vec![1,2,3];

foriin&v{

println!("{}",i);

}

Loanteriorimprimedesdeunohastatres.Amedidaqueiteramoslosvectores,solosenosproporcionanreferenciasasuselementos.vensimismoestomadoprestadodemanerainmutable,loquesetraduceenquenopodamoscambiarlomientrasloiteramos:

letmutv=vec![1,2,3];

foriin&v{

println!("{}",i);

v.push(34);

}

Heaquielerror:

ElLenguajedeProgramacionRust

177ReferenciasyPréstamo

Page 178: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

error:cannotborrow`v`asmutablebecauseitisalsoborrowedasimmutable

v.push(34);

^

note:previousborrowof`v`occurshere;theimmutableborrowprevents

subsequentmovesormutableborrowsof`v`untiltheborrowends

foriin&v{

^

note:previousborrowendshere

foriin&v{

println!(“{}”,i);

v.push(34);

}

^

Nopodemosmodificarvdebidoaqueestatomadoprestadoporelciclo.

usodespuesdeliberacion(useafterfree)

Lasreferenciasnodebenvivirpormastiempoqueelrecursoalcualestasapuntan.Rustchequearalosámbitosdetusreferenciasparaasegurarsedequeestoseacierto.

SiRustnoverificaraestapropiedad,podriamosaccidentalmenteusarunareferenciainvalida.Porejemplo:

lety:&i32;

{

letx=5;

y=&x;

}

println!("{}",y);

Obtenemoselsiguienteerror:

ElLenguajedeProgramacionRust

178ReferenciasyPréstamo

Page 179: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

error:`x`doesnotlivelongenough

y=&x;

^

note:referencemustbevalidfortheblocksuffixfollowingstatement0at

2:16...

lety:&i32;

{

letx=5;

y=&x;

}

note:...butborrowedvalueisonlyvalidfortheblocksuffixfollowing

statement0at4:18

letx=5;

y=&x;

}

Enotraspalabras,yesvalidosoloparaelámbitoendondexexiste.Tanprontocomoxseva,sehaceinvalidohacerlereferencia.Esporelloqueelerrordicequeelpréstamo,‘novivelosuficiente’(‘doesn’tlivelongenough’)yaquenoesvalidoporlacantidaddetiempocorrecta.

Elmismoproblemaocurrecuandolareferenciaesdeclaradaantesdelavariablealacualhacereferencia.Estoesdebidoaquelosrecursosdentrodelmismoámbitosonliberadosenordenopuestoalordenenelquefuerondeclarados:

lety:&i32;

letx=5;

y=&x;

println!("{}",y);

Obtenemosesteerror:

ElLenguajedeProgramacionRust

179ReferenciasyPréstamo

Page 180: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

error:`x`doesnotlivelongenough

y=&x;

^

note:referencemustbevalidfortheblocksuffixfollowingstatement0at

2:16...

lety:&i32;

letx=5;

y=&x;

println!("{}",y);

}

note:...butborrowedvalueisonlyvalidfortheblocksuffixfollowing

statement1at3:14

letx=5;

y=&x;

println!("{}",y);

}

Enelejemploanterior,yesdeclaradaantesquex,significandoqueyvivemasquex,locualnoestapermitido.

ElLenguajedeProgramacionRust

180ReferenciasyPréstamo

Page 181: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%TiemposdeVida

EstaguíaesunadelastrespresentandoelsistemadepertenenciadeRust.EstaesunadelascaracterísticasmasúnicasyatractivasdeRust,conlaquelosdesarrolladoresRustdebenestarbienfamiliarizados.LapertenenciaescomoRustlograsuobjetivomayor,seguridadenelmanejodememoria.Existenunospocosconceptosdistintos,cadaunoconsupropiocapitulo:

pertenencia,elconceptoprincipal[préstamo][borrowing],ysuscaracterísticaasociada‘referencias’tiemposdevida,laqueleesahora

Estostrescapítulosestánrelacionados,yenorden.Necesitarasleerlostresparaentendercompletamenteelsistemadepertenencia.

MetaAntesdeentrarendetalle,dosnotasimportantesacercadelsistemadepertenencia.

Rusttienefocoenseguridadyvelocidad.Rustlograesosobjetivosatravezdemuchas‘abstraccionesdecerocosto’,loquesignificaqueenRust,lasabstraccionescuestantanpococomoseaposibleparahacerlasfuncionar.Elsistemadepertenenciaesunejemploprimordialdeunaabstraccióndecerocosto.Todoelanálisisdelqueestaremoshablandoenlapresenteguíaesllevadoacaboentiempodecompilación.Nopagasningúncostoentiempodeejecuciónporningunadeestasfacilidades.

Sinembargo,estesistematieneciertocosto:lacurvadeaprendizaje.MuchosusuariosnuevosRustexperimentanalgoquenosotrosdenominamos‘pelearconelcomprobadordepréstamo’(‘fightingwiththeborrowchecker’),situaciónenlacualelcompiladordeRustserehusaacompilarunprogramaelcualelautorpiensavalido.EstoocurreconfrecuenciadebidoaqueelmodelomentaldelprogramadoracercadecomofuncionalapertenencianoconcuerdaconlasreglasactualesimplementadasenRust.Probablementetuexperimentescosassimilaresalcomienzo.Sinembargo,haybuenasnoticias:otrosdesarrolladoresRustexperimentadosreportanqueunavezquetrabajanconlasreglasdelsistemadepertenenciaporunperiododetiempo,peleancadavezmenosconelcomprobadordepréstamo.

Conesoenmente,aprendamosacercadelostiemposdevida.

Tiemposdevida

ElLenguajedeProgramacionRust

181TiemposdeVida

Page 182: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Prestarunareferenciaaotrorecursodelquealguienmasesdueñopuedesercomplicado.Porejemplo,imaginaesteconjuntodeoperaciones:

Obtengounhandleaalgúntipoderecurso.Teprestounareferenciaaelrecurso.Decidoqueheterminadoconelrecurso,ylolibero,mientrastodavíatieneslareferenciaael.Tudecidesusarelrecurso.

Ohno!Tureferenciaestaapuntandoaunrecursoinvalido.Estoesllamadounpunterocolganteousodespuésdeliberación,cuandoelrecursoesmemoria.

Paraarreglaresto,tenemosqueasegurarnosqueelpasocuatronuncaocurradespuésdelpasotres.ElsistemadepertenenciadeRustllevaestoacaboatravésdeunconceptodenominadotiemposdevida,loscualesdescribenelámbitoenelcualunareferenciaesvalida.

Cuandotenemosunafunciónquetomaunareferenciacomoargumento,podemosserimplícitosoexplícitosacercadeltiempodevidadelareferencia:

//implicito

fnfoo(x:&i32){

}

//explicito

fnbar<'a>(x:&'ai32){

}

El'aselee‘eltiempodevidaa’.Técnicamente,todareferenciaposeeuntiempodevidaasociadoaella,peroelcompiladortepermiteomitirlasencasoscomunes.Antesquelleguemosaeso,analicemoselpedazodecódigoexplícito:

fnbar<'a>(...)

Anteriormentehablamosunpocoacercadelasintaxisdefunciones,peronodiscutimoslos<>sdespuésdeunnombredefunción.Unafunciónpuedetener‘parámetrosgenéricos’entrelos<>s,ylostiemposdevidasonuntipodeparámetrogenérico.Discutiremosotrostiposdegenericosmastardeenellibro,peroporahora,enfoquémonossoloenelaspectodelostiemposdevida.

Usamos<>paradeclararnuestrostiemposdevida.Estodicequebarposeeuntiempodevida,'a.Dehabertenidoreferenciascomoparámetros,hubieselucidodeestamanera:

ElLenguajedeProgramacionRust

182TiemposdeVida

Page 183: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnbar<'a,'b="">(...)

Entoncesennuestralistadeparámetros,usamoslostiemposdevidaquehemosnombrado:

...(x:&'ai32)

Dehaberqueridounareferencia&mut,pudimoshaberhecholosiguiente:

...(x:&'amuti32)

Sicomparas&muti32con&'amuti32,sonlomismo,essoloqueeltiempodevida'asehametidoentreel&yelmuti32.Leemos&muti32como‘unareferenciamutableauni32’y&'amuti32como‘unareferenciamutableauni32coneltiempodevida'a’.

En structsTambiénnecesitarastiemposdevidaexplícitoscuandotrabajesconstructs:

structFoo<'a>{

x:&'ai32,

}

fnmain(){

lety=&5;//estoeslomismoque`let_y=5;lety=&_y;`

letf=Foo{x:y};

println!("{}",f.x);

}

Comopuedesver,losstructspuedentambiéntenertiemposdevida.Enunaformasimilaralasfunciones,

structFoo<'a>{

#x:&'ai32,

#}

declarauntiempodevida,y

ElLenguajedeProgramacionRust

183TiemposdeVida

Page 184: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#structFoo<'a>{

x:&'ai32,

#}

haceusodeel.Entonces,porquenecesitamosuntiempodevidaaquí?NecesitamosasegurarnosquecualquierreferenciaaunFoonopuedavivirmasquelareferenciaauni32queestecontiene.

bloquesimplImplementemosunmetodoenFoo:

structFoo<'a>{

x:&'ai32,

}

impl<'a>Foo<'a>{

fnx(&self)->&'ai32{self.x}

}

fnmain(){

lety=&5;//estoeslomismoque`let_y=5;lety=&_y;`

letf=Foo{x:y};

println!("xes:{}",f.x());

}

Comopuedesver,necesitamosdeclararuntiempodevidaparaFooenlalineaimpl.Repetimos'adosveces,justocomoenfunciones:impl<'a>defineuntiempodevida'a,yFoo<'a>haceusodeel.

MultiplestiempodevidaSiposeesmultiplesreferencias,puedeshacerusodeelmismotiempodevidamultiplesveces:

fnx_o_y<'a>(x:&'astr,y:&'astr)->&'astr{

#x

#}

ElLenguajedeProgramacionRust

184TiemposdeVida

Page 185: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Loanteriordicequeambosxyyvivenporelmismoámbito,yqueelvalorderetornotambiénestavivoparadichoámbito.Sihubiesesqueridoquexyytuviesendiferentestiemposdevida,pudistehaberhechousodemultiplesparámetrosdetiemposdevida:

fnx_o_y<'a,'b>(x:&'astr,y:&'bstr)->&'astr{

#x

#}

Enesteejemplo,xyytienendiferentesámbitosvalidos,peroelvalorderetornotieneelmismotiempodevidaquex.

PensandoenámbitosUnaformadepensaracercadelostiemposdevidaesvisualizarelámbitoenelcualesvalidaunareferencia.Porejemplo:

fnmain(){

lety=&5;//-+yentraenambito

//|

//stuff//|

//|

}//-+ysaledeambito

AgregandonuestroFoo:

structFoo<'a>{

x:&'ai32,

}

fnmain(){

lety=&5;//-+yentraenambito

letf=Foo{x:y};//-+fentraenambito

//stuff//|

//|

}//-+fyysalendeambito

Nuestrofvivedentrodeelámbitodey,esporelloquetodofunciona.Quepasaríadelocontrario?Elsiguientecódigonofuncionaria:

ElLenguajedeProgramacionRust

185TiemposdeVida

Page 186: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

structFoo<'a>{

x:&'ai32,

}

fnmain(){

letx;//-+xentraenambito

//|

{//|

lety=&5;//---+yentraenambito

letf=Foo{x:y};//---+fentraenambito

x=&f.x;//||erroraqui

}//---+fyysalendeambito

//|

println!("{}",x);//|

}//-+xsaledeambito

Uff!Comopuedesveraqui,losámbitosdefyysonmenoresqueelámbitodex.Perocuandohacemosx=&f.x,hacemosaxunareferenciaaalgoqueestarporsalirdeámbito.

Lostiemposdevidaconnombresonunaformadedarlesadichosámbitosunnombre.Darleunnombreaalgoeselprimerpasohaciapoderhablaracercadeel.

'staticEltiempodevidadenominado‘static’esuntiempodevidaespecial.Esteseñalaquealgoposeeeltiempodevidadeelprogramacompleto.LamayoríadelosdesarrolladoresRustconocena'staticcuandolidianconcadenasdecaracteres:

letx:&'staticstr="Hola,mundo.";

Losliteralesdecadenasdecaracteresposeeneltipo&'staticstrpuestoquelareferenciaestasiempreviva:estossoncolocadosenelsegmentodedatosdelbinariofinal.Otroejemplosonlasglobales:

staticFOO:i32=5;

letx:&'statici32=&FOO;

Loanterioragregauni32aelsegmentodedatosdeelbinario,yxesunareferenciaael.

Elisiondetiemposdevida

ElLenguajedeProgramacionRust

186TiemposdeVida

Page 187: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Rustsoportaunainferenciadetipospoderosaenloscuerposdefunción,peroestaprohibidoenlasfirmasdeelementospermitirrazonamientobasadoúnicamenteenlafirma.Sinembargo,porrazonesergonomicas,unainferenciasecundariamuyrestrictallamada“elisiondetiemposdevida”seaplicaenlasfirmasdefunción.La“elisiondetiemposdevida”infierebasandosesoloenloscomponentesdelafirmasinbasarseenelcuerpodelafunción,unicamneteinfiereparámetrosdetiemposdevida,yhaceestoconsolotresreglasfácilmentememorizableseinambiguas.Todoestohacealaelisiondetiemposdevidaunatajoparaescribirunafirma,sinnecesidaddeocultarlostiposinvolucradospuestoaqueinferencialocalcompletaseraaplicadaaellos.

Cuandosehabladeelisiondetiemposdevida,usamoselterminotiempodevidadeentradaytiempodevidadesalida.Untiempodevidadeentradaesuntiempodevidaasociadoconunparámetrodeunafunción,yuntiempodevidadesalidaesuntiempodevidaasociadoconelvalorderetornodeunafunción.Porejemplo,lasiguientefuncióntieneuntiempodevidadeentrada:

fnfoo<'a>(bar:&'astr)

Estaposeeuntiempodevidadesalida:

fnfoo<'a>()->&'astr

Lasiguientetieneuntiempodevidaenambasposiciones:

fnfoo<'a>(bar:&'astr)->&'astr

Heaquilastresreglas:

Cadatiempodevidaelididoenlosargumentosdeunafunciónseconvierteenunparámetrodetiempodevidadistinto.

Siexisteexactamenteunsolotiempodevidadeentrada,elididoono,esetiempodevidaesasignadoatodoslostiemposdevidaelididosenlosvaloresderetornodeesafunción.

Siexistenmultiplestiemposdevidadeentrada,perounadeelloses&selfo&mutself,eltiempodevidadeselfesasignadoatodoslostiemposdevidadesalidaelididos.

Delocontrario,esunerrorelidiruntiempodevidadesalida.

Ejemplos

ElLenguajedeProgramacionRust

187TiemposdeVida

Page 188: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Heaquialgunosejemplosdefuncionescontiemposdevidaelididos.Hemospareadocadaejemplodeuntiempodevidaelididoconsuformaexpandida.

fnprint(s:&str);//elidido

fnprint<'a>(s:&'astr);//expandido

fndebug(lvl:u32,s:&str);//elidido

fndebug<'a>(lvl:u32,s:&'astr);//expandido

//Enelejemploanterior,`lvl`nonecesitauntiempodevidadebidoaquenoesunareferencia(`&`).Sololascosasrelacionadasconreferencias(comoun`struct`quecontieneunareferencia)necesitantiemposdevida.

fnsubstr(s:&str,until:u32)->&str;//elidido

fnsubstr<'a>(s:&'astr,until:u32)->&'astr;//expandido

fnget_str()->&str;//ILLEGAL,noinputs

fnfrob(s:&str,t:&str)->&str;//ILEGAL,dosentradas

fnfrob<'a,'b="">(s:&'astr,t:&'bstr)->&str;//Expandido:Tiempodevidadesalidaesambiguo

fnget_mut(&mutself)->&mutT;//elidido

fnget_mut<'a>(&'amutself)->&'amutT;//expanded

fnargs(&mutself,args:&[T])->&mutCommand//elidido

fnargs<'a,'b,=""T:ToCStr="">(&'amutself,args:&'b[T])->&'amutCommand//expanded

fnnew(buf:&mut[u8])->BufWriter;//elidido

fnnew<'a>(buf:&'amut[u8])->BufWriter<'a>//expanded

ElLenguajedeProgramacionRust

188TiemposdeVida

Page 189: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Mutabilidad

Mutabilidad,eslahabilidadqueunacosaposeeparasercambiada,funcionaunpocodiferenteenRustqueenotroslenguajes.Elprimeraspectodelamutabilidadesquenoestahabilitadapordefecto:

letx=5;

x=6;//error!

Podemosintroducirmutabilidadconlapalabrareservadamut:

letmutx=5;

x=6;//nohayproblema!

Estoesunenlaceavariablemutable.Cuandounenlaceavariableesmutable,significaquetienespermitidocambiaraloqueelenlaceapunta.Entonces,enelejemploanterior,noestacambiandoelvalorenx,encambio,elenlacecambiodeuni32aotro.

Sideseascambiaraqueapuntaelenlaceavariable,necesitarasunareferenciamutable:

letmutx=5;

lety=&mutx;

yesunenlaceavariableinmutableaunareferenciamutable,loquesignificaquenopuedesasociaryaotracosa(y=&mutz),peropuedesmutarloqueseaaloqueyestaasociado(*y=5).Unadiferenciamuysutil.

Porsupuesto,sinecesitasambascosas:

letmutx=5;

letmuty=&mutx;

Ahoraypuedeserasociadoaotrovalor,yelvalorqueestareferenciandopuedesercambiado.

Esimportantenotarquemutespartedeunpatron,demaneratalquepuedashacercosascomo:

let(mutx,y)=(5,6);

fnfoo(mutx:i32){

#}

ElLenguajedeProgramacionRust

189Mutabilidad

Page 190: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

MutabilidadInteriorvs.MutabilidadExteriorSinembargo,cuandodecimosquealgoes‘immutable’enRust,estonosignificaquenopuedasercambiado:loquedecimosesquealgotiene‘mutabilidadexterior’.Considera,porejemplo,Arc<T>:

usestd::sync::Arc;

letx=Arc::new(5);

lety=x.clone();

Cuandollamamosaclone(),elArc<T>necesitaactualizarelcontadordereferencias.Apesardequenohemosusadoningúnmutaquí,xesunenlaceinmutable,tampocotomamos&mut5oalgunamas.Entonces,queestapasando?

Paraentenderesto,debemosvolveralnúcleodelafilosofíaqueguíaaRust,seguridadenelmanejodememoria,yelmecanismoatravésdelcualRustlagarantiza,elsistemadepertenencia,ymasespecíficamente,elpréstamo:

Puedestenerunouotrodeestosdostiposdeprestamo,peronolosdosalmismotiempo:

unaomasreferencias(&T)aunrecurso,exactamenteunareferenciamutable(&mutT).

Entonces,esaesladefiniciónrealde‘inmutabilidad’:essegurotenerdosapuntadores?EnelcasodeArc<T>’s,si:lamutaciónestacompletamentecontenidadentrodelaestructuraensimisma.Noestadisponiblealusuario.Porestarazón,retornaclone()&Ts.Siproporcionase&mutTs,seriaunproblema.

Otrostiposcomolosdelmodulostd::cell,poseenloopuesto:mutabilidadinterior.Porejemplo:

usestd::cell::RefCell;

letx=RefCell::new(42);

lety=x.borrow_mut();

RefCelproporcionareferencias&mutaloquecontienenatravesdelmetodoborrow_mut().Noesestopeligroso?Quetalsihacemos:

ElLenguajedeProgramacionRust

190Mutabilidad

Page 191: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::cell::RefCell;

letx=RefCell::new(42);

lety=x.borrow_mut();

letz=x.borrow_mut();

#(y,z);

Esto,enefecto,harápánicoentiempodeejecución.EstoesloqueRefCellhace:aplicalasreglasdepréstamodeRustentiempodeejecución,yhacepanic!ossidichasreglassonvioladas.LoanteriornospermiteacercarnosaotroaspectodelasreglasdemutabilidaddeRust.Hablemosacercadeelloprimero.

MutabilidadaniveldecamposLamutabilidadesunapropiedaddeunpréstamo(&mut)ounenlaceavariable(letmut).Estosetraduceenque,porejemplo,nopuedestenerunstructconalgunoscamposmutablesyotrosinmutables:

structPunto{

x:i32,

muty:i32,//nope

}

Lamutabilidaddeunstructestaensuenlaceavariable:

structPunto{

x:i32,

y:i32,

}

letmuta=Punto{x:5,y:6};

a.x=10;

letb=Punto{x:5,y:6};

b.x=10;//error:cannotassigntoimmutablefield`b.x`

Sinembargo,usandoCell<T>,puedesemularmutabilidadaniveldecampos:

ElLenguajedeProgramacionRust

191Mutabilidad

Page 192: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::cell::Cell;

structPunto{

x:i32,

y:Cell<i32>,

}

letpunto=Punto{x:5,y:Cell::new(6)};

punto.y.set(7);

println!("y:{:?}",punto.y);

Estoimprimiráy:Cell{value:7}.Hemosactualizadoydemanerasatisfactoria.

ElLenguajedeProgramacionRust

192Mutabilidad

Page 193: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Estructuras(Structs)

Lasestructuras(structs)sonunaformadecreartiposdedatosmascomplejos.Porejemplo,siestuviéramoshaciendocálculosqueinvolucrarancoordenadasenunespacio2D,necesitaríamosambos,unvalorxyunvalory:

letorigen_x=0;

letorigen_y=0;

unastructnospermitecombinarambosenunúnicotipodedatosunificado:

structPunto{

x:i32,

y:i32,

}

fnmain(){

letorigen=Punto{x:0,y:0};//origin:Punto

println!("Elorigenestaen({},{})",origen.x,origen.y);

}

Haymuchascosaspasandoacá,asíqueanalicémosloporpartes.Declaramosunaestructuraconlapalabrareservadastruct,seguidadeunnombre.Porconvención,losstructscomienzanconunaletramayúsculaysoncamelcased:PuntoEnElEspacio,noPunto_En_El_Espacio.

Podemoscrearunainstanciadenuestrastructvialet,comoesusual,perousamosunasintaxisestiloclave:valorparaasignarcadacampo.Elordernonecesitaserelmismoqueenladeclaraciónoriginal.

Finalmente,debidoaquetenemosnombresdecampos,podemosaccederaellosatravésdelanotacióndepuntos:origen.x.

Losvaloresenstructssoninmutablespordefecto,justocomolosdemásenlacesavariablesenRust.Usamutparahacerlosmutables:

ElLenguajedeProgramacionRust

193Estructuras

Page 194: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

structPunto{

x:i32,

y:i32,

}

fnmain(){

letmutpunto=Punto{x:0,y:0};

punto.x=5;

println!("Elorigenestaen({},{})",punto.x,punto.y);

}

EstoimprimiráElorigenestaen(5,0).

Rustnosoportamutabilidaddecamposaniveldelenguaje,esporelloquenopuedesescribiralgocomoesto:

structPunto{

mutx:i32,

y:i32,

}

Lamutabilidadesunapropiedaddelenlaceavariable,nodelaestructuraensimisma.Siestasacostumbradoalamutabilidadaniveldecampos,estopuedeparecerunpocoextrañoalprincipio,perosimplificalascosasdemanerasignificativa.Inclusotepermitehaceralascosasmutablessoloporunperiodocortodetiempo:

structPunto{

x:i32,

y:i32,

}

fnmain(){

letmutpunto=Punto{x:0,y:0};

punto.x=5;

letpunto=punto;//ahora,estenuevoenlaceavariablenopuedesercambiado

punto.y=6;//estocausaunerror

}

Sintaxisdeactualización

ElLenguajedeProgramacionRust

194Estructuras

Page 195: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Unastructpuedeincluir..paraindicarquedeseasusarunacopiadealgúnotrostructparaalgunosdelosvalores.Porejemplo:

structPunto3d{

x:i32,

y:i32,

z:i32,

}

letmutpunto=Punto3d{x:0,y:0,z:0};

punto=Punto3d{y:1,..punto};

Loanterior,asignaapuntounnuevoy,peromantienelosantiguosvaloresdexyz.Tampocotienequeserlamismaestructura,puedeshacerusodeestasintaxiscuandocreasnuevas,yestacopiaralosvaloresquenoespecifiques:

#structPunto3d{

#x:i32,

#y:i32,

#z:i32,

#}

letorigen=Punto3d{x:0,y:0,z:0};

letpunto=Punto3d{z:1,x:2,..origen};

Tuplaestructuras(Tuplestructs)Rustposeeotrotipodedatosqueescomounhíbridoentreunatuplayunastruct,llamadotullaestructura(tuplestruct).Lastuplaestructurasposeenunnombre,perosuscamposno:

structColor(i32,i32,i32);

structPunto(i32,i32,i32);

Lasdosanterioresnoserániguales,inclusosiposeenlosmismosvalores:

#structColor(i32,i32,i32);

#structPunto(i32,i32,i32);

letnegro=Color(0,0,0);

letorigen=Punto(0,0,0);

Casisiempreesmejorusarunastructqueunatuplestruct.Ensulugar,podríamosescribirColorandPuntoasí:

ElLenguajedeProgramacionRust

195Estructuras

Page 196: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

structColor{

rojo:i32,

azul:i32,

verde:i32,

}

structPunto{

x:i32,

y:i32,

z:i32,

}

Ahora,tenemosnombres,enlugardeposiciones.Losbuenosnombressonimportantes,yconunastruct,tenemosnombres.

Hayuncasoenelcualunatuplaestructuraesmuyútil,yesunatuplaestructuraconunsoloelemento.Sedenominapatrónnuevotipo(newtype),puestoaquecrearunnuevotipo,distintoaelvalorquecontiene,expresandosupropiasemántica:

structPulgadas(i32);

letlongitud=Pulgadas(10);

letPulgadas(longitud_enteros)=longitud;

println!("lalongitudes{}pulgadas",longitud_enteros);

Comonotaras,puedesextraerelenterocontenidoconunletdedestructuración,justocomoenlastuplasregulares.Enestecaso,elletPulgadas(longitud_enteros)asigna10alongitud_enteros.

Estructurastipo-unitario(unit-likestructs)Puedesdefinirunastructsinningúnmiembro:

structElectron;

Dichastructesdenominadatipo-unitario(unit-like)porsusemejanzaalatuplavacía,(),algunasvecesllamadaunidad(unit).Comounatuplaestructura,defineunnuevotipo.

Loanterioresraramenteutilensimismo(aunquealgunasvecespuedeservircomountipomarcador),peroencombinaciónconotrascaracterísticas,puedetornarseútil.Porejemplo,unalibreríapuederequerircrearunaestructuraqueimplementaciertotraitparamanejar

ElLenguajedeProgramacionRust

196Estructuras

Page 197: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

eventos.Denoposeerningunadataparaguardarenlaestructura,simplementepuedescrearunastructtipo-unitario.

ElLenguajedeProgramacionRust

197Estructuras

Page 198: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Enumeraciones

Unaenumeración(enum)enRustesuntipoquerepresentadataquepuedeserunadeunconjuntodevariantesposible:

enumMensaje{

Salir,

CambiarColor(i32,i32,i32),

Mover{x:i32,y:i32},

Escribir(String),

}

Cadavariantepuedeopcionalmentetenerdataasociada.Lasintaxisparaladefinicióndevariantesessemejantealasintaxisusadaparadefinirestructuras(structs):puedestenervariantessindatos(comolasestructurastipo-unitario),variantescondatanombrada,yvariantescondatasinnombres(comotuplaestructuras).Sinembargo,adiferenciadelasdefinicionesdeestructuras,unenumesunúnicotipo.Unvalordeunenumpuedecoincidirconcualquieradelasvariantes.Porestarazón,unenumesdenominadoalgunasvecesun‘tiposuma’(‘sumtype’):elconjuntodevaloresposiblesdelenumeslasumadelosconjuntosdevaloresposiblesparacadavariante.

Utilizamoslasintaxis::parahacerusodecadavariante:lasvariantesestándentrodelámbitodelenum.Loquehacequelosiguienteseavalido:

#enumMensaje{

#Mover{x:i32,y:i32},

#}

letx:Mensaje=Mensaje::Mover{x:3,y:4};

enumTurnoJuegoMesa{

Mover{celdas:i32},

Pasar,

}

lety:TurnoJuegoMesa=TurnoJuegoMesa::Mover{celdas:1};

AmbasvariantesposeenelnombreMover,perodebidoaquesuámbitoesdentrodelnombredelenum,ambaspuedenserusadassinconflicto.

Unvalordeuntipoenumcontieneinformaciónacercadecualvariantees,enadiciónacualquierdataasociadacondichavariante.Estoesalgunasvecesdenominado‘unionetiquetada’(‘taggedunion’),puestoaqueladataincluyeuna‘etiqueta’(‘tag’)queindicaquetipoes.Elcompiladorusaestainformaciónparaasegurarsequeestemosaccediendoaladataenelenumdemanerasegura.Porejemplo,nopuedessimplementetratardedestructurarunvalorcomosiestefuereunadelasposiblesvariantes:

ElLenguajedeProgramacionRust

198Enumeraciones

Page 199: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnprocesar_cambio_color(msj:Mensaje){

letMensaje::CambiarColor(r,v,a)=msj;//compile-timeerror

}

Nosoportarestetipodeoperacionespuedelucirunpocolimitante,peroesunalimitaciónquepodemossuperar.Existendosmaneras,implementandolaigualdadpornuestracuenta,oatravésdeelpatternmatchingconexpresionesmatch,queaprenderásenlasiguientesección.TodavíanosabemoslosuficientedeRustparaimplementarlaigualdadpornuestracuenta,peroloveremosenlaseccióntraits.

ConstructorescomofuncionesUnconstructordeunenumpuedesertambiénusadocomounafunción.Porejemplo:

#enumMensaje{

#Escribir(String),

#}

letm=Mensaje::Escribir("Hola,mundo".to_string());

Eslomismoque

#enumMensaje{

#Escribir(String),

#}

fnfoo(x:String)->Mensaje{

Mensaje::Escribir(x)

}

letx=foo("Hola,mundo".to_string());

Estonoesinmediatamenteutilparanosotros,perocuandolleguemosalosclosures,hablaremosacercadepasarfuncionescomoargumentosaotrasfunciones.Porejemplo,conlositeradores,podemosconvertirunvectordeStringsenunvectordeMessage::Escribirs:

#enumMensaje{

#Escribir(String),

#}

letv=vec!["Hola".to_string(),"Mundo".to_string()];

letv1:Vec<Mensaje>=v.into_iter().map(Mensaje::Escribir).collect();

ElLenguajedeProgramacionRust

199Enumeraciones

Page 200: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

ElLenguajedeProgramacionRust

200Enumeraciones

Page 201: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Match

Amenudo,unsimpleif/elsenoessuficiente,debidoaquetienesmasdedosopcionesposibles.También,lascondicionespuedensercomplejas.Rustposeeunapalabrareservada,match,quetepermitereemplazarconstruccionesif/elsecomplicadasconalgomaspoderoso.Echaunvistazo:

letx=5;

matchx{

1=>println!("uno"),

2=>println!("dos"),

3=>println!("trees"),

4=>println!("cuatro"),

5=>println!("cinco"),

_=>println!("otracosa"),

}

matchtomaunaexpresiónyluegobifurcabasadoensuvalor.Cadabrazodelaramatienelaformavalor=>expresión.Cuandoelvalorcoincide,laexpresióndelbrazoesevaluada.Esllamadomatchporeltermino‘patternmatching’,delcualmatchesunaimplementación.Hayunasecciónenteraacercadelospatronesquecubretodoslospatronesposibles.

Entonces,cualeslagranventaja?Bueno,hayunaspocas.Primeroquetodo,matchimponechequeodeagotamiento(‘exhaustivenesschecking’).Veselultimobrazo,elqueposeeelguiónbajo(_)?Siremovemosesebrazo,Rustnosproporcionaraunerror:

error:non-exhaustivepatterns:`_`notcovered

Enotraspalabras,Rustestatratandodedecirnosqueolvidamosunvalor.Debidoaquexesunentero,Rustsabequexpuedetenerunnumerodevaloresdiferentes-porejemplo,6.Sinel_,sinembargo,nohaybrazoquepuedacoincidir,yenconsecuenciaRustserehusaacompilarelcódigo._actúacomoun‘brazoqueatrapatodo’.Siningunodelosotrosbrazoscoincide,elbrazoconel_lohará,ypuestoquetenemosdicho‘brazoqueatrapatodo’,tenemosahoraunbrazoparacadavalorposibledex,ycomoresultado,nuestroprogramacompilarasatisfactoriamente.

matchestambiénunaexpresión,loquesignificaquelopodemosusarenelladoderechodeunletodirectamenteendondeunaexpresiónseausada:

ElLenguajedeProgramacionRust

201Match

Page 202: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

letx=5;

letnumber=matchx{

1=>"uno",

2=>"dos",

3=>"tres",

4=>"cuatro",

5=>"cinco",

_=>"otracosa",

};

Algunasvecesesunabuenaformadeconvertiralgodeuntipoaotro.

Haciendo matchenenumsOtrousoimportantedelapalabrareservadamatchesparaprocesarlasposiblesvariantesdeunaenum:

enumMensaje{

Salir,

CambiarColor(i32,i32,i32),

Mover{x:i32,y:i32},

Escribir(String),

}

fnsalir(){/*...*/}

fncambiar_color(r:i32,g:i32,b:i32){/*...*/}

fnmover_cursor(x:i32,y:i32){/*...*/}

fnprocesar_mensaje(msj:Mensaje){

matchmsj{

Mensaje::Salir=>salir(),

Mensaje::CambiarColor(r,g,b)=>cambiar_color(r,g,b),

Mensaje::Mover{x:x,y:y}=>mover_cursor(x,y),

Mensaje::Escribir(s)=>println!("{}",s),

};

}

Otravez,elcompiladordeRustchequeaagotamiento,demandandoquetengasunbrazoparacadavariantedelaenumeración.Sidejasunoporfuera,Rustgeneraraunerrorentiempodecompilación,amenosqueuses_.

Adiferenciadelosusospreviosdematch,nopuedesusardelasentenciaifparahaceresto.Puedeshacerusodeunasentenciaifletquepuedeservistacomounaformaabreviadadematch.

ElLenguajedeProgramacionRust

202Match

Page 203: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Patrones

LospatronessonbastantecomunesenRust.Losusamosenenlacesavariable,sentenciasmatch,yotroscasos.Embarquemonosenuntourtorbellinoportodaslascosasquelospatronessoncapacesdehacer!

Unrepasorápido:puedesprobarpatronescontraliteralesdirectamente,y_actúacomouncasocualquiera:

letx=1;

matchx{

1=>println!("uno"),

2=>println!("dos"),

3=>println!("tres"),

_=>println!("cualquiera"),

}

Imprimeuno.

MultiplespatronesPuedesprobarmultiplespatronescon|:

letx=1;

matchx{

1|2=>println!("unoodos"),

3=>println!("tres"),

_=>println!("cualquiera"),

}

Loanteriorimprimeunoodos.

DestructuracionSiposeesuntipodedatoscompuesto,comounstruct,puedesdestructurarlodentrodeunpatron:

ElLenguajedeProgramacionRust

203Patrones

Page 204: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

structPunto{

x:i32,

y:i32,

}

letorigen=Punto{x:0,y:0};

matchorigen{

Punto{x,y}=>println!("({},{})",x,y),

}

Puedesusar:paradarleunnombrediferenteaunvalor.

structPunto{

x:i32,

y:i32,

}

letorigen=Punto{x:0,y:0};

matchorigen{

Punto{x:x1,y:y1}=>println!("({},{})",x1,y1),

}

Sisolonosimportanalgunosvalores,notenemosquedarlenombresatodos:

structPunto{

x:i32,

y:i32,

}

letorigen=Punto{x:0,y:0};

matchorigen{

Punto{x,..}=>println!("xes{}",x),

}

Estoimprimexes0.

Puedeshacerestetipodepruebasencualquiermiembro,nosoloelprimero:

ElLenguajedeProgramacionRust

204Patrones

Page 205: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

structPunto{

x:i32,

y:i32,

}

letorigen=Punto{x:0,y:0};

matchorigen{

Punto{y,..}=>println!("yes{}",y),

}

Loanteriorimprimeyes0.

Estecomportamientode‘destructuracion’funcionaencualquiertipodedatoscompuesto,comotuplasoenums.

IgnorandoenlacesavariablesPuedesusar_enunpatronparaignorartantoeltipocomoelvalor.

Porejemplo,heaquíunmatchcontraunResult<T,E>:

#letalgun_valor:Result<i32,&'staticstr>=Err("Hubounerror");

matchalgun_valor{

Ok(valor)=>println!("valorobtenido:{}",valor),

Err(_)=>println!("haocurridounerror"),

}

Enelprimerbrazo,enlazamoselvalordentrodelavarianteOkalavariablevalor.PeroenelbrazoErrusamos_paraignorarelerrorespecifico,ysoloimprimirunmensajedeerrorgeneral.

_esvalidoencualquierpatronquecreeunenlaceavariable.Tambiénpuedeserutilparaignorarporcionesdeunaestructuramasgrande:

fncoordenada()->(i32,i32,i32){

//generaryretornaralgúntipodetupladetreselementos

#(1,2,3)

}

let(x,_,z)=coordenada();

Aquí,asociamosamboselprimeryultimoelementodelatuplaaxyzrespectivamente,ignorandoelelementodelamitad.

ElLenguajedeProgramacionRust

205Patrones

Page 206: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Similarmente,puedesusar..enunpatrónparaignorarmultiplesvalores.

enumTuplaOpcional{

Valor(i32,i32,i32),

Faltante,

}

letx=TuplaOpcional::Valor(5,-2,3);

matchx{

TuplaOpcional::Valor(..)=>println!("Tuplaobtenida!"),

TuplaOpcional::Faltante=>println!("Sinsuerte."),

}

EstoimprimeTuplaobtenida!.

refyrefmutSideseasobtenerunareferencia,debesusarlapalabrareservadaref:

letx=5;

matchx{

refr=>println!("Referenciaa{}obtenida",r),

}

ImprimeReferenciaa5obtenida.

Acá,lardentrodelmatchposeeeltipo&i32.Enotraspalabraslapalabrareservadarefcreaunareferencia,paraserusadadentrodelpatrón.Sinecesitasunareferenciamutablerefmutfuncionaradelamismamanera:

letmutx=5;

matchx{

refmutrm=>println!("Referenciamutablea{}obtenida",rm),

}

RangosPuedesprobarunrangodevalorscon...:

ElLenguajedeProgramacionRust

206Patrones

Page 207: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

letx=1;

matchx{

1...5=>println!("unoalcinco"),

_=>println!("cualquiercosa"),

}

Estoimprimeunoalcinco.

Losrangossonusadosmayormenteconenterosycharss:

letx='';

matchx{

'a'...'j'=>println!("letratemprana"),

'k'...'z'=>println!("letratardia"),

_=>println!("algomas"),

}

Thisprintsalgomas.

EnlacesavariablePuedesasociarvaloresanombrescon@:

letx=1;

matchx{

[email protected]=>println!("valorderango{}obtenido",e),

_=>println!("loquesea"),

}

Thisprintsvalorderango1obtenido.Loanterioresutilcuandodeseeshacerunmatchcomplicadoaunapartedeunaestructuradedatos:

ElLenguajedeProgramacionRust

207Patrones

Page 208: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#[derive(Debug)]

structPersona{

nombre:Option<String>,

}

letnombre="Steve".to_string();

letmutx:Option<Persona>=Some(Persona{nombre:Some(nombre)});

matchx{

Some(Persona{nombre:refa@Some(_),..})=>println!("{:?}",a),

_=>{}

}

DichocódigoimprimeSome("Steve"):hemosasociadoelnombreinternoaa.

Siusas@con|,necesitasasegurartedequeelnombreseaasociadoencadapartedelpatron:

letx=5;

matchx{

[email protected]|[email protected]=>println!("valorderango{}obtenido",e),

_=>println!("loquesea"),

}

GuardiasPuedesintroducirguardiasmatch(‘matchguards’)conif:

enumEnteroOpcional{

Valor(i32),

Faltante,

}

letx=EnteroOpcional::Value(5);

matchx{

EnteroOpcional::Valor(i)ifi>5=>println!("Enteromayoracincoobtenido!"),

EnteroOpcional::Valor(..)=>println!("Enteroobtenido!"),

EnteroOpcional::Faltante=>println!("Sinsuerte."),

}

EstoimprimeEnteroobtenido!".

Siestasusandoifconmultiplespatrones,elifaplicaaamboslados:

ElLenguajedeProgramacionRust

208Patrones

Page 209: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

letx=4;

lety=false;

matchx{

4|5ify=>println!("si"),

_=>println!("no"),

}

Loanteriorimprimeno,debidoaqueelifaplicaael4|5completo,ynosoloal5.Enotraspalabras,laprecedenciadelifsecomportadelasiguientemanera:

(4|5)ify=>...

ynoasí:

4|(5ify)=>...

MezclayMatchUff!Esofueunmontóndeformasdiferentesparaprobarcosas,ytodaspuedensermezcladasyprobadas,dependiendodelosqueestéshaciendo:

matchx{

Foo{x:Some(refnombre),y:None}=>...

}

Lospatronessonmuypoderosos.Hazbuenusodeellos.

ElLenguajedeProgramacionRust

209Patrones

Page 210: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%SintaxisdeMétodos

Lasfuncionessongeniales,perosideseasllamarbastantesenalgunadata,puedetornarseincomodo.Consideraestecódigo:

baz(bar(foo));

Pudiéramosleerestodeizquierdaaderecha,veríamosentonces‘bazbarfoo’.Peroesenoeselordenenelcuallasfuncionessonllamadas,elordendehecho,esdeadentrohaciaafuera:‘foobarbaz’.Noseriaexcelentesipudiéramoshacerlo:

foo.bar().baz();

Porsuerte,comohabráspodidodeducirdelapreguntaanterior,porsupuestoquepodemos!Rustproveelahabilidaddeusarladenominada‘sintaxisdellamadaamétodos’(‘methodcallsyntax’)atravésdelapalabrareservadaimpl.

LlamadasamétodosAsífuncionan:

structCirculo{

x:f64,

y:f64,

radio:f64,

}

implCirculo{

fnarea(&self)->f64{

std::f64::consts::PI*(self.radio*self.radio)

}

}

fnmain(){

letc=Circulo{x:0.0,y:0.0,radio:2.0};

println!("{}",c.area());

}

Loanteriorimprimira12.566371.

Hemosconstruidounastructrepresentandoauncirculo.Despuésescribimosunbloqueimplydentrodeel,definimosunmétodo,area.

ElLenguajedeProgramacionRust

210SintaxisdeMétodos

Page 211: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Losmétodosrecibenunprimerparámetroespecial,delcualexistentresvariantes:self,&self,y&mutself.Puedespensaracercadeesteprimerparámetrocomoelfooenfoo.bar().Lastresvariantescorrespondenalostrestiposdecosasquefoopodríaser:selfsiessolounvalorenlapila,&selfsiesunareferenciay&mutselfsiesunareferenciamutable.Debidoaqueproporcionamoselparámetro&selfaarea,podemosusarlojustocomocualquierotro.ComoconocemosqueesunCirculo,podemosaccederaradiocomoloharíamosconcualquierotrastruct.

Deberíamosusarpordefecto&self,asícomopreferirtambiénelpréstamoporencimadelatomadepertenenciayrecibirreferenciasinmutablesenvezdemutables,enloposible.Heaquíunejemplodelastresvariantes:

structCirculo{

x:f64,

y:f64,

radio:f64,

}

implCircle{

fnreferencia(&self){

println!("recibiendoaselfcomounareferencia!");

}

fnreferencia_mutable(&mutself){

println!("trecibiendoaselfcomounareferenciamutable!");

}

fntoma_pertenecia(self){

println!("tomandopertenenciadeself!");

}

}

LlamadasamétodosencadenaEntonces,ahorasabemoscomollamaraunmétodo,comofoo.bar().Peroquehayacercadenuestroejemplooriginal,foo.bar().baz()?Sedenomina‘encadenamientodemétodos’(‘methodchaining’).Veamosunejemplo:

ElLenguajedeProgramacionRust

211SintaxisdeMétodos

Page 212: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

structCirculo{

x:f64,

y:f64,

radio:f64,

}

implCirculo{

fnarea(&self)->f64{

std::f64::consts::PI*(self.radio*self.radio)

}

fnagrandar(&self,incremento:f64)->Circulo{

Circulo{x:self.x,y:self.y,radio:self.radio+incremento}

}

}

fnmain(){

letc=Circulo{x:0.0,y:0.0,radio:2.0};

println!("{}",c.area());

letd=c.agrandar(2.0).area();

println!("{}",d);

}

Observaelvalorderetorno:

#structCirculo;

#implCirculo{

fnagrandar(&self,incremento:f64)->Circulo{

#Circulo}}

SolodecimosqueretornamosunCirculo.Conestemétodo,podemosagrandarunnuevoCirculoauntamañoarbitrario.

FuncionesasociadasPuedestambiéndefinirfuncionesasociadasquenotomenelparámetroself.HeaquíunpatronmuycomúnencódigoRust:

ElLenguajedeProgramacionRust

212SintaxisdeMétodos

Page 213: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

structCirculo{

x:f64,

y:f64,

radio:f64,

}

implCirculo{

fnnew(x:f64,y:f64,radio:f64)->Circulo{

Circulo{

x:x,

y:y,

radio:radio,

}

}

}

fnmain(){

letc=Circulo::new(0.0,0.0,2.0);

}

Esta‘funciónasociada’construyeunnuevoCirculo.NotaquelasfuncionesasociadassonllamadasconlasintaxisStruct::funcion(),enlugarderef.metodo().Otroslenguajesllamanalasfuncionesasociadas‘métodosestáticos’

ElpatrónConstructor(Builder)DigamosquequeremosquenuestrosusuariospuedancrearCirculos,perosololespermitiremosdarvaloresalaspropiedadesqueseanrelevantesparaellos.Delocontrario,losatributosxyyserán0.0,yelradiosera1.0.Rustnoposeesobrecargademétodos,argumentosconnombreoargumentosvariables.Seempleaelpatronbuilderensulugar.Dichopatronluceasí:

structCirculo{

x:f64,

y:f64,

radio:f64,

}

implCirculo{

fnarea(&self)->f64{

std::f64::consts::PI*(self.radio*self.radio)

}

}

structConstructorCirculo{

x:f64,

ElLenguajedeProgramacionRust

213SintaxisdeMétodos

Page 214: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

y:f64,

radio:f64,

}

implConstructorCirculo{

fnnew()->ConstructorCirculo{

ConstructorCirculo{x:0.0,y:0.0,radio:1.0,}

}

fnx(&mutself,coordenada:f64)->&mutConstructorCirculo{

self.x=coordenada;

self

}

fny(&mutself,coordenada:f64)->&mutConstructorCirculo{

self.y=coordenada;

self

}

fnradio(&mutself,radio:f64)->&mutConstructorCirculo{

self.radio=radio;

self

}

fnfinalizar(&self)->Circulo{

Circulo{x:self.x,y:self.y,radio:self.radio}

}

}

fnmain(){

letc=ConstructorCirculo::new()

.x(1.0)

.y(2.0)

.radio(2.0)

.finalizar();

println!("area:{}",c.area());

println!("x:{}",c.x);

println!("y:{}",c.y);

}

Loquehemoshechoescrearotrastruct,ConstructorCirculo.Hemosdefinidonuestrosmétodosconstructoresenella.Tambiénhemosdefinidonuestrométodoarea()enCirculo.HemosagregadootrométodoenConstructorCirculo:finalizar().EstemétodocreanuestroCirculodesdeelconstructor.Ahora,hemosusadoelsistemadetiposparahacervalernuestrosintereses:podemosusarlosmétodosenConstructorCirculoparacrearCirculosenlaformaquedecidamos.

ElLenguajedeProgramacionRust

214SintaxisdeMétodos

Page 215: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Vectores

Un‘vector’esunarreglodinámico,implementadocomoeltipodelabibliotecaestándarVec<T>.LaTsignificaquepodemostenervectoresdecualquiertipo(echaunvistazoalcapitulode[genéricos][generics]paramasinformación).Losvectoressiemprealojansusdatosenelmontículo.Puedescrearvectoresconlamacrovec!:

letv=vec![1,2,3,4,5];//v:Vec<i32>

(Notaqueadiferenciadelamacroprintln!quehemosusadoenelpasado,usamoscorchetes[]conlamacrovec!.Rusttepermiteusarcualquieraencualquiersituación,enestaoportunidadesporpuraconvención)

Existeunaformaalternativadevec!pararepetirunvalorinicial:

letv=vec![0;10];//diezceros

AccediendoaelementosParaobtenerelvalorenunindiceenparticulardelvector,usamos[]s:

letv=vec![1,2,3,4,5];

println!("Eltercerelementodeves{}",v[2]);

Losindicescomienzandesde0,entonces,eltercerelementoesv[2].

IterandoUnavezposeasunvector,puedesiteraratravésdesuselementosconfor.Haytresversiones:

ElLenguajedeProgramacionRust

215Vectores

Page 216: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

letmutv=vec![1,2,3,4,5];

foriin&v{

println!("Unareferenciaa{}",i);

}

foriin&mutv{

println!("Unareferenciamutablea{}",i);

}

foriinv{

println!("Tomandopertenenciadelvectorysuelemento{}",i);

}

Losvectoresposeenmuchosotrosmétodosútiles,acercadeloscualespuedesleerensudocumentation

ElLenguajedeProgramacionRust

216Vectores

Page 217: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%CadenasdeCaracteres

Lascadenasdecaracteressonunconceptoimportanteadominarparacualquierprogramador.ElsistemademanejodecadenasdecaracteresenRustesunpocodistintoaldeotroslenguajes,debidoasufocoenprogramacióndesistemas.Siemprequeposeasunaestructuradedatosdetamañovariable,lascosaspuedenponerseunpocodifíciles,ylascadenasdecaracteressonunaestructuradedatosquepuedevariarentamaño.Dichoesto,lascadenasdecaracteresdeRusttambiénfuncionandemaneradiferentequeenalgunosotroslenguajesdeprogramacióndesistemas,comoC.

Entremosenlosdetalles.Una‘cadenadecaracteres’(‘string’)esunasecuenciadevaloresescalaresUnicodecodificadacomounflujodebytesUTF-8.TodaslascadenasdecaracteresestángarantizadasaserunacodificaciónvalidadesecuenciasUTF-8.Adicionalmente,yadiferenciadeotroslenguajesdesistemas,lascadenasdecaracteresnosonterminadasennullypuedencontenerbytesnull.

Rustposeedostiposprincipalesdecadenasdecaracteres:&stryString.Hablemosprimeroacercade&str.Estossondenominados‘pedazosdecadenasdecaracteres’(‘stringslices’).LosliteralesStringsondeltipo&'staticstr`:

letsaludo="Hola.";//saludo:&'staticstr

Estacadenadecaracteresesasignadaestáticamente,significandoqueesalmacenadadentrodenuestroprogramacompilado,yexisteporladuracióncompletadesuejecución.Elenlacesaludoesunareferenciaaunacadenaasignadaestéticamente.Lospedazosdecadenasdecaracteresposeenuntamañofijo,ynopuedensermutados.

Porotrolado,unString,esunacadenadecaracteresasignadadesdeelmontículo.Dichacadenapuedecrecer,ytambiénestagarantizadaserUTF-8.LosStringsoncreadoscomúnmenteatravésdelaconversióndeunpedazodecadenadecarácterusandoelmétodoto_string.

letmuts="Hola".to_string();//muts:String

println!("{}",s);

s.push_str(",mundo.");

println!("{}",s);

LosStringsharancoercionaun&strconun&:

ElLenguajedeProgramacionRust

217CadenasdeCaracteres

Page 218: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnrecibe_pedazo(pedazo:&str){

println!("Recibí:{}",pedazo);

}

fnmain(){

lets="Hola".to_string();

recibe_pedazo(&s);

}

Estacoerciónnoocurreparalasfuncionesqueaceptanunodelostraits&str’senlugarde&str.Porejemplo,TcpStream::connectposeeunparámetrodetipoToSocketAddrs.Un&strestabienperounStringdebeserexplícitamenteconvertidousando&*.

usestd::net::TcpStream;

TcpStream::connect("192.168.0.1:3000");//parametro&str

letcadena_direccion="192.168.0.1:3000".to_string();

TcpStream::connect(&*cadena_direccion);//convirtiendocadena_direcciona&str

VerunStringcomoun&stresbarato,peroconvertirel&straunStringinvolucraasignacióndememoria.Nohayrazónparahaceresoamenosqueseanecesario!

IndexadoDebidoaquelascadenasdecaracteressonUTF-8validos,nosoportanindexado:

lets="hola";

println!("Laprimeraletradeses{}",s[0]);//ERROR!!!

Usualmente,elaccesoaunvectorcon[]esmuyrápido.Pero,puestoaquecadacaráctercodificadoenunacadenaUTF-8puedetenermultiplesbytes,debesrecorrertodalacadenaparaencontrarlanᵗʰletradeunacadena.Estaesunaoperaciónsignificativamentemascara,ynoqueremosgenerarconfusiones.Incluso,‘letra’noesexactamentealgodefinidoenUnicode.Podemosescogerveraunacadenadecaracterescomobytesindividuales,ocomocodepoints:

ElLenguajedeProgramacionRust

218CadenasdeCaracteres

Page 219: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

lethachiko="忠犬ハチ公";

forbinhachiko.as_bytes(){

print!("{},",b);

}

println!("");

forcinhachiko.chars(){

print!("{},",c);

}

println!("");

Loanteriorimprime:

229,191,160,231,138,172,227,131,143,227,131,129,229,133,172,

忠,犬,ハ,チ,公,

Comopuedesver,haymasbytesquecaracteres(chars).

Puedesobteneralgosimilaraunindicedeestaforma:

#lethachiko="忠犬ハチ公";

letperro=hachiko.chars().nth(1);//algocomohachiko[1]

Estoenfatizaquetenemosquecaminardesdeelprincipiodelalistadechars.

Cortado(Slicing)Puedesobtenerunpedazodeunacadenadecaracteresconlasintaxisdecortado:

letperro="hachiko";

lethachi=&perro[0..5];

Peronotaqueestossondesplazamientosdebyte,nodesplazamientosdecharacter.Entonces,losiguientefallaraentiempodeejecución:

letperro="忠犬ハチ公";

lethachi=&perro[0..2];

conesteerror:

ElLenguajedeProgramacionRust

219CadenasdeCaracteres

Page 220: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

thread'

'panickedat'index0and/or2in`忠犬ハチ公`donotlieon

characterboundary'

ConcatenaciónSiposeesunString,puedesconcatenarleun&stralfinal:

lethola="Hola".to_string();

letmundo="mundo!";

lethola_mundo=hola+mundo;

PerositienesdosStrings,necesitasun&:

lethola="Hola".to_string();

letmundo="mundo!".to_string();

lethola_mundo=hola+&world;

Estoesporque&Stringpuedehacercoercionautomáticaaun&str.Estacaracterísticaesdenominada‘coercionesDeref’.

ElLenguajedeProgramacionRust

220CadenasdeCaracteres

Page 221: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Genéricos

Algunasveces,cuandoseescribeunafunciónounaestructuradedatos,podríamosdesearqueestapudiesefuncionarconmultiplestiposdeargumentos.EnRustpodemoslograrestoatravésdelosgenéricos.Losgenéricossonllamados‘polimorfismoparametrico’enlateoríadetipos,loquesignificaquesontiposofuncionesqueposeenmultiplesformas(‘poly’demultiple,‘morph’deforma)sobreundeterminadoparámetro(‘parametrico’).

Decualquiermodo,suficienteacercadeteoríadetipos,veamosunpocodecódigogenérico.LabibliotecaestándardeRustproveeuntipo,Option<T>,elcualesgenérico:

enumOption<T>{

Some(T),

None,

}

Laparte<T>,lacualhasvistounascuantasvecesanteriormente,indicaqueesteesuntipodedatosgenérico.Dentrodeladeclaracióndenuestroenum,dondeseaqueveamosunaTsustituimosesetipoporelmismotipousadoenelgenérico.HeaquíunejemplodelusodeOption<T>,conalgunosanotacionesdetipoextra:

letx:Option<i32>=Some(5);

Enladeclaracióndeltipo,decimosOption<i32>.NotacuansimilarestoluceestoaOption<T>.Entonces,enesteOption,Tposeeelvalordei32.Enelladoderechodelbinding,hacemosunSome(T),endondeTes5.Debidoaque5esuni32,ambosladoscoinciden,yRustesfeliz.Denohabercoincidido,hubiésemosobtenidounerror:

letx:Option=Some(5);

//error:mismatchedtypes:expected`core::option::Option`,

//found`core::option::Option<_>`(expectedf64butfoundintegralvariable)

EsonosignificaquenopodamoscrearOption<T>squecontenganunf64.Simplementedebencoincidir:

letx:Option<i32>=Some(5);

lety:Option<f64>=Some(5.0f64);

Muybueno.Unadefinición,multiplesusos.

Losgenéricosnodebennecesariamentesergenéricossobreunsolotipo.ConsideraotrotiposimilarenlabibliotecaestándardeRust,Result<T,E>:

ElLenguajedeProgramacionRust

221Genéricos

Page 222: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

enumResult<T,E>{

Ok(T),

Err(E),

}

Estetipoesgenéricosobredostipos:TyE.Porcierto,lasletrasmayusculaspuedensercualquiera.PudimoshaberdefinidoResult<T,E>como:

enumResult<A,Z>{

Ok(A),

Err(Z),

}

dehaberquerido.LaconvencióndicequeelprimerparametrogenericodebeserT,de‘tipo’,yqueusemosEpara‘error’.ARust,sinembargonoleimporta.

EltipoResult<T,E>seusapararetornarelresultadodeunacomputación,conlaposibilidadderetornarunerrorencasodequedichacomputaciónnohayasidoexitosa.

FuncionesgenéricasPodemosescribirfuncionesquetomentiposgenéricosconunasintaxissimilar:

fnrecibe_cualquier_cosa<T>(x:T){

//haceralgoconx

}

Lasintaxisposeedospartes:el<T>dice“estafunciónesgenericasobreuntipo,T”,ylapartex:Tdice“xposeeeltipoT.”

Multiplesargumentospuedentenerelmismotipo:

fnrecibe_dos_cosas_del_mismo_tipo<T>(x:T,y:T){

//...

}

Pudimoshaberescritounaversionquerecibemultiplestipos:

fnrecibe_dos_cosas_de_distintos_tipos<T,U>(x:T,y:U){

//...

}

ElLenguajedeProgramacionRust

222Genéricos

Page 223: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

StructsgenericosTambiénpuedesalmacenaruntipogenéricoenunaestructura:

structPunto<T>{

x:T,

y:T,

}

letorigen_entero=Punto{x:0,y:0};

letorigen_flotante=Punto{x:0.0,y:0.0};

Similarmentealasfunciones,lasección<T>esendondedeclaramoslosparámetrosgenéricos,despuésdeellohacemosusodex:Tenladeclaracióndeltipo,también.

Cuandodeseamosagregarunaimplementaciónparalaestructuragenérica,simplementedeclaraselparámetrodetipodespuésdeimpl:

#structPunto<T>{

#x:T,

#y:T,

#}

#

impl<T>Punto<T>{

fnintercambiar(&mutself){

std::mem::swap(&mutself.x,&mutself.y);

}

}

Hastaahorasolohasvistogenéricosqueaceptanabsolutamentecualquiertipo.Estassonútilesenmuchoscasos,yahasvistoOption<T>,ymastardeconocerascontenedoresuniversalescomoVec<T>.Porotrolado,avecesquerrásintercambiaresaflexibilidadpormayorpoderexpresivo.Leeacercadelimitestraitparaverporqueycomo.

ElLenguajedeProgramacionRust

223Genéricos

Page 224: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Traits

UntraitesunafacilidaddellenguajequeleindicacompiladordeRustacercadelafuncionalidadqueuntipodebeproveer.

Recuerdaslapalabrareservadaimpl?,usadaparallamaraunafunciónconlasintaxisdemétodos?

structCirculo{

x:f64,

y:f64,

radio:f64,

}

implCirculo{

fnarea(&self)->f64{

std::f64::consts::PI*(self.radio*self.radio)

}

}

Lostraitssonsimilares,exceptoquedefinimosuntraitconsololafirmademétodoyluegoimplementamoseltraitparalaestructura.Así:

structCirculo{

x:f64,

y:f64,

radio:f64,

}

traitTieneArea{

fnarea(&self)->f64;

}

implTieneAreaforCirculo{

fnarea(&self)->f64{

std::f64::consts::PI*(self.radio*self.radio)

}

}

Comopuedesver,elbloquetraitlucemuysimilaraelbloqueimpl,peronodefinimosunbloque,sololafirmadetipos.Cuandoimplementamosuntrait,usamosimplTraitforItem,envezdesoloimplItem.

Limitestraitparafuncionesgenéricas

ElLenguajedeProgramacionRust

224Traits

Page 225: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Lostraitssonútilesporquepermitenauntipohacerciertaspromesasacercadesucomportamiento.Lafuncionesgenéricaspuedenexplotarestopararestringirlostiposqueaceptan.Consideraestafunción,lacualnocompila:

fnimrimir_area(figura:T){

println!("Estafiguratieneunareade{}",figura.area());

}

Rustsequeja:

error:nomethodnamed`area`foundfortype`T`inthecurrentscope

DebidoaqueTpuedeserdecualquiertipo,nopodemosestarsegurosqueimplementaelmétodoarea.Peropodemosagregaruna‘restriccióndetrait’anuestroTgenérico,asegurándonosdequeloimplemente:

#traitTieneArea{

#fnarea(&self)->f64;

#}

fnimrimir_area<T:TieneArea>(shape:T){

println!("Estafiguratieneunareade{}",figura.area());

}

Lasintaxis<T:TieneArea>setraduceen“cualquiertipoqueimplementeeltraitTieneArea.”.Aconsecuenciadequelostraitsdefinenfirmasdetiposdefunción,podemosestarsegurosquecualquiertipoqueimplementeTieneAreatendráunmétodo.area().

Heaquíunejemploextendidodecomoestofunciona:

ElLenguajedeProgramacionRust

225Traits

Page 226: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

traitTieneArea{

fnarea(&self)->f64;

}

structCirculo{

x:f64,

y:f64,

radio:f64,

}

implTieneAreaforCirculo{

fnarea(&self)->f64{

std::f64::consts::PI*(self.radio*self.radio)

}

}

structCuadrado{

x:f64,

y:f64,

lado:f64,

}

implTieneAreaforCuadrado{

fnarea(&self)->f64{

self.lado*self.lado

}

}

fnimrimir_area<T:TieneArea>(figura:T){

println!("Estafiguratieneunareade{}",figura.area());

}

fnmain(){

letc=Circulo{

x:0.0f64,

y:0.0f64,

radio:1.0f64,

};

lets=Cuadrado{

x:0.0f64,

y:0.0f64,

lado:1.0f64,

};

imrimir_area(c);

imrimir_area(s);

}

Esteprogramaproducelasalida:

ElLenguajedeProgramacionRust

226Traits

Page 227: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Estafiguratieneunareade3.141593

Estafiguratieneunareade1

Comopuedesver,imrimir_areaahoraesgenérica,perotambiénaseguraquehallamosproporcionadolostiposcorrectos.Sipasamosuntipoincorrecto:

imrimir_area(5);

Obtenemosunerrorentiempodecompilación:

error:thetrait`TieneArea`isnotimplementedforthetype`_`[E0277]

LimitesdetraitparaestructurasgenericasTusestructurasgenéricaspuedenbeneficiarsetambiéndelasrestriccionesdetrait.Todoloquenecesitasesagregarlarestriccióncuandodeclaraslosparámetrosdetipos.AcontinuaciónunnuevotipoRectangulo<T>ysuoperaciónes_cuadrado:

structRectangulo<T>{

x:T,

y:T,

ancho:T,

altura:T,

}

impl<T:PartialEq>Rectangulo<T>{

fnes_cuadrado(&self)->bool{

self.ancho==self.altura

}

}

fnmain(){

letmutr=Rectangulo{

x:0,

y:0,

ancho:47,

altura:47,

};

assert!(r.es_cuadrado());

r.altura=42;

assert!(!r.es_cuadrado());

}

ElLenguajedeProgramacionRust

227Traits

Page 228: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

es_cuadrado()necesitachequearquelosladossoniguales,yparaellolostiposdebenserdeuntipoqueimplementeeltraitcore::cmp::PartialEq:

implRectangulo{...}

Ahora,unrectángulopuedeserdefinidoenfuncióndecualquiertipoquepuedasercomparadoporigualdad.

HemosdefinidounanuevaestructuraRectanguloqueaceptanúmerosdecualquierprecision,objetosdecualquiertiposiempreycuandopuedansercomparadosporigualdad.PodríamoshacerlomismoparanuestrasestructurasTieneArea,CuadradoyCirculo?Si,peroestasnecesitanmultiplicación,yparatrabajarconesonecesitamossabermasdelostraitsdeoperadores.

ReglasparalaimplementacióndetraitsHastaahora,solohemosagregadoimplementacionesdetraitsaestructuras,peropuedesimplementarcualquiertraitparacualquiertipo.Técnicamente,podriamosimplementarTieneAreaparai32:

traitTieneArea{

fnarea(&self)->f64;

}

implTieneAreafori32{

fnarea(&self)->f64{

println!("estoestonto");

*selfasf64

}

}

5.area();

Seconsiderapobreestiloimplementarmétodosenesostiposprimitivos,auncuandoesposible.

Estopuedelucircomoelviejooeste,perohaydosrestriccionesacercadelaimplementacióndetraitsqueprevienenquelascosassesalgandecontrol.Laprimeraesquesieltraitnoestadefinidoentuámbito,noaplica.Heaquíunejemplo:labibliotecaestándarproveeuntraitWritequeagregafuncionalidadextraalosFiles,posibilitandolaE/Sdearchivos.Pordefecto,unFilenotendríasusmétodos:

ElLenguajedeProgramacionRust

228Traits

Page 229: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

letmutf=std::fs::File::open("foo.txt").ok().expect("Nosepudoabrirfoo.txt");

letbuf=b"cualquiercosa";//literaldecadenadebytes.buf:&[u8;8]

letresultado=f.write(buf);

#resultado.unwrap();//ignorarelerror

Heaquielerror:

error:type`std::fs::File`doesnotimplementanymethodinscopenamed`write`

letresultado=f.write(buf);

^~~~~~~~~~

NecesitamosprimerohacerusedeltraitWrite:

usestd::io::Write;

letmutf=std::fs::File::open("foo.txt").ok().expect("Nosepudoabrirfoo.txt");

letbuf=b"cualquiercosa";

letresultado=f.write(buf);

#resultado.unwrap();//ignorarelerror

Loanteriorcompilarasinerrores.

Estosignificaqueinclusosialguienhacealgomalocomoagregarmétodosai32,noteafectara,amenosquehagasusedeesetrait.

Hayunarestricciónmasacercadelaimplementacióndetraits:unodelosdosbienseaeltraitoeltipoparaelcualestasescribiendolaimpl,debeserdefinidoporti.Entonces,podríamosimplementareltraitTieneAreaparaeltipoi32,puestoqueTieneAreaestaennuestrocódigo.PerosiintentáramosimplementarToString,untraitproporcionadoporRustparai32,nopodríamos,debidoaquenieltraitoeltipoestánennuestrocódigo.

Unaultimacosaacercadelostraits:lasfuncionesgenéricasconunlimitedetraitusan‘monomorfizacion’(‘monomorphization’)(mono:uno,morfos:forma),yporellosondespachadasestáticamente.Quesignificaesto?Echaunvistazoaelcapituloacercadeobjetostraitparamasdetalles.

MultipleslimitesdetraitHasvistoquepuedeslimitarunparámetrodetipogenéricoconuntrait:

ElLenguajedeProgramacionRust

229Traits

Page 230: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnfoo<T:Clone>(x:T){

x.clone();

}

Sinecesitasmasdeunlimite,puedeshacerusode+:

usestd::fmt::Debug;

fnfoo<T:Clone+Debug>(x:T){

x.clone();

println!("{:?}",x);

}

TnecesitaahoraserambosCloneyDebug.

LaclausulawhereEscribirfuncionesconsolounospocostiposgenéricosyunpequeñonumerodelimitesdetraitnoestanfeo,peroamedidaqueelnumeroseincrementa,lasintaxissevuelveunpocoextraña:

usestd::fmt::Debug;

fnfoo<T:Clone,K:Clone+Debug>(x:T,y:K){

x.clone();

y.clone();

println!("{:?}",y);

}

Elnombredelafunciónestalejosalaizquierda,ylalistadeparámetrosestalejosaladerecha.Loslimitesdetraitseinterponenenlamitad.

Rusttieneunasolución,ysellama‘clausulawhere’:

ElLenguajedeProgramacionRust

230Traits

Page 231: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::fmt::Debug;

fnfoo<T:Clone,K:Clone+Debug>(x:T,y:K){

x.clone();

y.clone();

println!("{:?}",y);

}

fnbar<T,K>(x:T,y:K)whereT:Clone,K:Clone+Debug{

x.clone();

y.clone();

println!("{:?}",y);

}

fnmain(){

foo("Hola","mundo");

bar("Hola","mundo");

}

foo()usalasintaxisdemostradapreviamente,ybar()usaunaclausulawhere.Todoloquenecesitasesdejarloslimitesporfueracuandodefinastusparámetrosdetipoyluegoagregarunwheredespuésdelalistadeparámetros.Paralistasmaslargas,espaciosenblancopuedenseragregados:

usestd::fmt::Debug;

fnbar<T,K>(x:T,y:K)

whereT:Clone,

K:Clone+Debug{

x.clone();

y.clone();

println!("{:?}",y);

}

Dichaflexibilidadpuedeagregarclaridadensituacionescomplejas.

Laclausulawhereestambiénmaspoderosaquelasintaxismassimple.Porejemplo:

ElLenguajedeProgramacionRust

231Traits

Page 232: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

traitConvertirA<Salida>{

fnconvertir(&self)->Salida;

}

implConvertirA<i64>fori32{

fnconvertir(&self)->i64{*selfasi64}

}

//puedeserllamadaconT==i32

fnnormal<T:ConvertirA<i64>>(x:&T)->i64{

x.convertir()

}

//puedeserllamadaconT==i64

fninversa<T>()->T

//pestoesuserConvertirAcomosifuera"ConvertirA<i64>"

wherei32:ConvertirA<T>{

42.convertir()

}

Loanteriordemuestraunacaracterísticaadicionaldewhere:permitelimitesenlosqueelladoizquierdoesuntipoarbitrario(i32enestecaso),nosolounsimpleparámetrodetipo(comoT).

MetodospordefectoSiyasabescomounimplementadortípicodefiniráunmétodo,puedespermitiratutraitproporcionarunométodopordefecto:

traitFoo{

fnes_valido(&self)->bool;

fnes_invalido(&self)->bool{!self.es_valido()}

}

LosimplementadoresdeltraitFoonecesitanimplementares_valido(),perononecesitanimplementares_invalido().Loobtendránpordefecto.Tambiénpuedensobreescribirlaimplementaciónpordefectosilodesean:

ElLenguajedeProgramacionRust

232Traits

Page 233: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#traitFoo{

#fnes_valido(&self)->bool;

#

#fnes_invalido(&self)->bool{!self.es_valido()}

#}

structUsaDefault;

implFooforUsaDefault{

fnes_valido(&self)->bool{

println!("UsaDefault.es_validllamada.");

true

}

}

structSobreescribeDefault;

implFooforSobreescribeDefault{

fnes_valido(&self)->bool{

println!("SobreescribeDefault.es_validollamada.");

true

}

fnes_invalido(&self)->bool{

println!("SobreescribeDefault.es_invalidollamada!");

true//estaimplementacionesunaauto-contradiccion!

}

}

letdefault=UsaDefault;

assert!(!default.es_valido());//imprime"UsaDefault.es_validllamada."

letsobre=SobreescribeDefault;

assert!(sobre.is_invalid());//prints"SobreescribeDefault.es_invalidollamada!"

HerenciaAlgunasveces,implementaruntraitrequiereimplementarotro:

traitFoo{

fnfoo(&self);

}

traitFooBar:Foo{

fnfoobar(&self);

}

LosimplementadoresdeFooBardebentambiénimplementarFoo,deestamanera:

ElLenguajedeProgramacionRust

233Traits

Page 234: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#traitFoo{

#fnfoo(&self);

#}

#traitFooBar:Foo{

#fnfoobar(&self);

#}

structBaz;

implFooforBaz{

fnfoo(&self){println!("foo");}

}

implFooBarforBaz{

fnfoobar(&self){println!("foobar");}

}

SiolvidamosimplementarFoo,Rustnoslodira:

error:thetrait`main::Foo`isnotimplementedforthetype`main::Baz`[E0277]

ElLenguajedeProgramacionRust

234Traits

Page 235: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Drop

Ahoraquehemosdiscutidolostraits,hablemosdeuntraitparticularproporcionadoporlabibliotecaestándardeRust,Drop.EltraitDropproveeunaformadeejecutarcódigocuandounvalorsaledeámbito.Porejemplo:

structTieneDrop;

implDropforTieneDrop{

fndrop(&mutself){

println!("Dropeando!");

}

}

fnmain(){

letx=TieneDrop;

//hacemosalgo

}//xsaledeambitoaqui

Cuandoxsaledeámbitoalfinaldemain(),elcódigodeDropesejecutado.Dropposeeunmétodo,tambiéndenominadodrop().Dichométodotomaunareferenciamutableaself.

Esoestodo!LamecánicadeDropesmuysimple,sinembargo,hayalgunosdetalles.Porejemplo,losvaloressonliberados(dropped)enordenopuestoacomofuerondeclarados.Heaquíotroejemplo:

structExplosivo{

potencia:i32,

}

implDropforExplosivo{

fndrop(&mutself){

println!("BOOMmultiplicadopor{}!!!",self.potencia);

}

}

fnmain(){

letpetardo=Explosivo{potencia:1};

lettnt=Explosivo{potencia:100};

}

Loanteriorimprimira:

ElLenguajedeProgramacionRust

235Drop

Page 236: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

BOOMmultiplicadopor100!!!

BOOMmultiplicadopor1!!!

ElTNTsevaprimeroqueelpetardo,debidoquefuecreadodespués.Ultimoenentrar,primeroensalir.

EntoncesparaqueesbuenoDrop?Generalmente,esusadoparalimpiarcualquierrecursoasociadoaunstruct.Porejemplo,eltipoArc<T>esuntipoconconteodereferencias.CuandoDropesllamado,estedecrementaráelcontadordereferencias,ysielnumerototaldereferenciasescero,limpiaráelvalorsubyacente.

ElLenguajedeProgramacionRust

236Drop

Page 237: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%iflet

iflettepermitecombinarifyletparareducirelcostodealgunostiposdecoincidenciadepatrones.

Porejemplo,digamosquetenemosalgúntipodeOption<T>.QueremosllamaraunafunciónsobreelloencasodeserunSome<T>,peronohacernadasiesNone.Seriaalgoasí:

#letoption=Some(5);

#fnfoo(x:i32){}

matchoption{

Some(x)=>{foo(x)},

None=>{},

}

Notenemosqueusarmatchaquí,porejemplo,podríamosusarif:

#letoption=Some(5);

#fnfoo(x:i32){}

ifoption.is_some(){

letx=option.unwrap();

foo(x);

}

Ningunadeesasdosopcionesesparticularmenteatractiva.Podemosusarifletparahacerlomismo,perodemejorforma:

#letoption=Some(5);

#fnfoo(x:i32){}

ifletSome(x)=option{

foo(x);

}

Siunpatrónconcuerdasatisfactoriamente,asociacualquierparteapropiadadelvaloralosidentificadoresenelpatrón,paraluegoevaluarlaexpresión.Sielpatrónnoconcuerda,nopasanada.

Siquisierashaceralgoenelcasodequeelpatrónnoconcuerde,puedesusarelse:

ElLenguajedeProgramacionRust

237iflet

Page 238: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#letoption=Some(5);

#fnfoo(x:i32){}

#fnbar(){}

ifletSome(x)=option{

foo(x);

}else{

bar();

}

whilelet

Demanerasimilar,whileletpuedeserusadocuandodeseesiterarcondicionalmentemientraselvalorconcuerdeconciertopatrón.Conviertecódigocomoeste:

#letoption:Option<i32>=None;

loop{

matchoption{

Some(x)=>println!("{}",x),

_=>break,

}

}

Encódigocomoeste:

#letoption:Option<i32>=None;

whileletSome(x)=option{

println!("{}",x);

}

ElLenguajedeProgramacionRust

238iflet

Page 239: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%ObjetosTrait

Cuandoelcódigoinvolucrapolimorfismo,esnecesariounmecanismoparadeterminarqueversiónespecificadebeserejecutada.Dichomecanismoesdenominadodespacho.Haydosformasmayoresdedespacho:despachoestáticoydespachodinámico.SibienesciertoqueRustprefiereeldespachoestático,tambiénsoportadespachodinámicoatravésdeunmecanismollamado‘objetostrait’.

BasesPorelrestodeestecapitulo,necesitaremosuntraityalgunasimplementaciones.Creemosunosimple,Foo.FooposeeunsolométodoqueretornaunString.

traitFoo{

fnmetodo(&self)->String;

}

Tambiénimplementaremosestetraitparau8yString:

#traitFoo{fnmetodo(&self)->String;}

implFooforu8{

fnmetodo(&self)->String{format!("u8:{}",*self)}

}

implFooforString{

fnmetodo(&self)->String{format!("string:{}",*self)}

}

DespachoestáticoPodemosusareltraitparaefectuardespachoestáticomedianteelusodelimitesdetrait:

ElLenguajedeProgramacionRust

239ObjetosTrait

Page 240: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#traitFoo{fnmetodo(&self)->String;}

#implFooforu8{fnmetodo(&self)->String{format!("u8:{}",*self)}}

#implFooforString{fnmetodo(&self)->String{format!("string:{}",*self)}}

fnhacer_algo<T:Foo>(x:T){

x.metodo();

}

fnmain(){

letx=5u8;

lety="Hola".to_string();

hacer_algo(x);

hacer_algo(y);

}

Rustutiliza‘monomorfizacion’paraeldespachoestáticoenestecódigo.Loquesignificaquecrearaunaversiónespecialdehacer_algo()paraambosu8yString,reemplazandoluegoloslugaresdellamadaconinvocacionesaestasfuncionesespecializadas.Enotraspalabras,Rustgeneraalgoasí:

#traitFoo{fnmetodo(&self)->String;}

#implFooforu8{fnmetodo(&self)->String{format!("u8:{}",*self)}}

#implFooforString{fnmetodo(&self)->String{format!("string:{}",*self)}}

fnhacer_algo_u8(x:u8){

x.metodo();

}

fnhacer_algo_string(x:String){

x.metodo();

}

fnmain(){

letx=5u8;

lety="Hola".to_string();

hacer_algo_u8(x);

hacer_algo_string(y);

}

Loanteriorposeeunagranventaja:eldespachoestáticopermitequelasllamadasafunciónpuedanserinsertadasenlineadebidoaqueelreceptoresconocidoentiempodecompilación,ylainserciónenlineaesclaveparaunabuenaoptimizacion.Eldespachoestáticoesrápido,perovieneconunadesventaja:‘códigoinflado’(‘codebloat’),aconsecuenciadelasrepetidascopiasdelamismafunciónquesoninsertadasenelbinario,unaparacadatipo.

ElLenguajedeProgramacionRust

240ObjetosTrait

Page 241: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Ademas,loscompiladoresnosonperfectosypueden“optimizar”códigohaciendolomaslento.Porejemplo,funcionesinsertadasenlineademaneraansiosainflaranlacachedeinstrucciones(yelcachegobiernatodoanuestroalrededor).Esporelloque#[inline]y#[inline(always)]debenserusadasconcautela,yunarazónporlacualusardespachodinámicoesalgunasvecesmaseficiente.

Sinembargo,elcasocomúnesqueeldespachoestáticoseamaseficiente.Unopuedetenerunadelgadafunciónenvoltoriodespachadademaneraestáticaefectuandodespachodinámico,peronoviceversa,esdecir;lasllamadasestáticassonmasflexibles.Esporestoquelabibliotecaestándarintentaserdespachadadinámicamentesiempreycuandoseaposible.

DespachodinámicoRustproporcionadespachodinámicoatravésdeunafacilidaddenominada‘objetostrait’.Losobjetostrait,como&FoooBox<Foo>,sonvaloresnormalesquealmacenanunvalordecualquiertipoqueimplementaeltraitdeterminado,endondeeltipoprecisosolopuedeserdeterminadoentiempodeejecución.

Unobjetotraitpuedeserobtenidodeunapuntadorauntipoconcretoqueimplementeeltraitconvirtiéndolo(e.j.&xas&Foo)oaplicándolecoercion(e.j.usando&xcomounargumentoaunafunciónquerecibe&Foo).

Esascoercionesyconversionestambiénfuncionanparaapuntadorescomo&mutTa&mutFooyBox<T>aBox<Foo>,peroesoestodohastaelmomento.Lascoercionesyconversionessonidénticas.

Estaoperaciónpuedeservistacomoel‘borrado’delconocimientodelcompiladoracercadeltipoespecificodelapuntador,yesporelloquelosobjetostraitssonavecesreferidoscomoborradodetipos.

Volviendoaelejemploanterior,podemosusarelmismotraitparallevaracabodespachodinámicoconconversióndeobjetostrait:

ElLenguajedeProgramacionRust

241ObjetosTrait

Page 242: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#traitFoo{fnmetodo(&self)->String;}

#implFooforu8{fnmetodo(&self)->String{format!("u8:{}",*self)}}

#implFooforString{fnmetodo(&self)->String{format!("string:{}",*self)}}

fnhacer_algo(x:&Foo){

x.metodo();

}

fnmain(){

letx=5u8;

hacer_algo(&xas&Foo);

}

oatravesdelacoercion:

#traitFoo{fnmetodo(&self)->String;}

#implFooforu8{fnmetodo(&self)->String{format!("u8:{}",*self)}}

#implFooforString{fnmetodo(&self)->String{format!("string:{}",*self)}}

fnhacer_algo(x:&Foo){

x.method();

}

fnmain(){

letx="Hola".to_string();

hacer_algo(&x);

}

UnafunciónquerecibeunobjetotraitnoesespecializadaparacadaunodelostiposqueimplementanFoo:solounacopiaesgenerada,resultandoalgunasveces(peronosiempre)enmenosinflacióndecódigo.Sinembargo,eldespachodinámicovieneconelcostoderequerirlasllamadasmaslentasafuncionesvirtuales,efectivamenteinhibiendocualquierposibilidaddeinserciónenlineaylasoptimizacionesrelacionadas.

Porqueapuntadores?

Rust,adiferenciademuchoslenguajesadministrados,nocolocacosasdetrásdeapuntadorespordefecto,loquesetraduceenquelostipostengandiferentestamaños.Conocereltamañodeunvalorentiempodecompilaciónesimportanteparacosascomo:pasarlocomoargumentoaunafunción,moverloenlapilayasignarle(ydeasignarle)espacioenelmontículoparasualmacenamiento.

ParaFoo,necesitaríamostenerunvalorquepodríasermaspequeñoqueunString(24bytes)ounu8(1byte),asícomocualquierotrotipoquepuedaimplementarFooencratesdependientes(cualquiernumerodebytes).Nohayformadegarantizarqueeste

ElLenguajedeProgramacionRust

242ObjetosTrait

Page 243: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

ultimocasopuedafuncionarsilosvaloresnosonalmacenadosenunapuntador,puestoqueesosotrostipospuedenserdetamañoarbitrario.

Colocarelvalordetrásdeunapuntadorsignificaqueeltamañodelvalornoesrelevantecuandoestemoslanzandounobjetotraitporlosalrededores,soloeltamañodelapuntadorensimismo.

Representación

Losmétodosdeltraitpuedenserllamadosenunobjetotraitatravésdeunregistrodeapuntadoresafuncióntradicionalmentellamado‘vtable’(creadoyadministradoporelcompilador).

Losobjetostraitsonsimplesycomplejosalmismotiempo:surepresentationydistribuciónesbastantedirecta,peroexistenalgunosmensajesdeerrorunpocorarosyalgunoscomportamientossorpresivospordescubrir.

Comencemosporlomassimple,larepresentacióndeunobjetotraitentiempodeejecución.Elmodulostd::rawcontienestructscondistribucionesquesonigualdecomplicadasquelasdelostiposintegrados,incluyendolosobjetostrait:

#modfoo{

pubstructTraitObject{

pubdata:*mut(),

pubvtable:*mut(),

}

#}

Esoes,untraitobjectcomo&Fooconsistedeunapuntador‘data’yunapuntador‘vtable’.

Elapuntadordataapuntahacialosdatos(deuntipodesconocidoT)queguardaelobjetotrait,yelvtablepointerapuntaalavtable(tabledemetodosvirtuales’)(‘virtualmethodtable’)correspondientealaimplementacióndeFooparaT.

Unavtableesesencialmenteunastructdeapuntadoresafunción,apuntandoalsegmentoconcretodecódigomaquinaparacadaimplementacióndemetodo.Unallamadaametodocomoobjeto_trait.metodo()retornaraelapuntadorcorrectodesdelavtableyluegoharáunallamadadinámicadeeste.Porejemplo:

ElLenguajedeProgramacionRust

243ObjetosTrait

Page 244: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

structFooVtable{

destructor:fn(*mut()),

tamano:usize,

alineacion:usize,

metodo:fn(*const())->String,

}

//u8:

fnllamar_metodo_en_u8(x:*const())->String{

//elcompiladorgarantizaqueestafunciónsoloseallamada

//con`x`apuntandoaunu8

letbyte:&u8=unsafe{&*(xas*constu8)};

byte.metodo()

}

staticFoo_vtable_para_u8:FooVtable=FooVtable{

destructor:/*magiadelcompilador*/,

tamano:1,

alineacion:1,

//conversionaaunapuntadorafunción

metodo:llamar_metodo_en_u8asfn(*const())->String,

};

//String:

fnllamar_metodo_en_String(x:*const())->String{

//elcompiladorgarantizaqueestafunciónsoloseallamada

//con`x`apuntandoaunString

letstring:&String=unsafe{&*(xas*constString)};

string.metodo()

}

staticFoo_vtable_para_String:FooVtable=FooVtable{

destructor:/*magiadelcompilador*/,

//valoresparaunacomputadorade64bits,dividelosporlamitadparaunade32

tamano:24,

alineacion:8,

metodo:llamar_metodo_en_Stringasfn(*const())->String,

};

Elcampodestructorencadavtableapuntaaunafunciónquelimpiaratodoslosrecursosdeltipodelavtable:parau8estrivial,peroparaStringliberaramemoria.EstoesnecesarioparaadueñarsedeobjetostraitcomoBox<Foo>,quenecesitanlimpiaramboslaasignaciónBoxasícomoeltipointernocuandosalgandeámbito.Loscampostamanoy

ElLenguajedeProgramacionRust

244ObjetosTrait

Page 245: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

alineacionalmacenaneltamañodeltipoborrado,ysusrequerimientosdealineación;estossonesencialmentenousadosporelmomentopuestoquelainformaciónesembebidaeneldestructor,peroserausadaenelfuturo,amedidaquelosobjetostraitseanprogresivamentehechosmasflexibles.

SupongamosquetenemosalgunosvaloresqueimplementenFoo.LaformaexplicitadeconstrucciónyusodeobjetostraitFoopuedelucirunpococomo(ignorandolasincongruenciasentretipos:sonapuntadoresdecualquiermanera):

leta:String="foo".to_string();

letx:u8=1;

//letb:&Foo=&a;

letb=TraitObject{

//almacenalosdatos

data:&a,

//almacenalosmetodos

vtable:&Foo_vtable_para_String

};

//lety:&Foo=x;

lety=TraitObject{

//almacenalosdatos

data:&x,

//almacenalosmetodos

vtable:&Foo_vtable_para_u8

};

//b.metodo();

(b.vtable.metodo)(b.data);

//y.metodo();

(y.vtable.metodo)(y.data);

SeguridaddeObjetosNotodotraitpuedeserusadoparacrearunobjetotrait.Porejemplo,losvectoresimplementanClone,perosiintentamoscrearunobjetotrait:

letv=vec![1,2,3];

leto=&vas&Clone;

Obtenemosunerror:

ElLenguajedeProgramacionRust

245ObjetosTrait

Page 246: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

error:cannotconverttoatraitobjectbecausetrait`core::clone::Clone`isnotobject-safe[E0038]

leto=&vas&Clone;

^~

note:thetraitcannotrequirethat`Self:Sized`

leto=&vas&Clone;

^~

ElerrordicequeClonenoes‘seguroparaobjetos’(‘object-safe’).Sololostraitsquesonsegurosparaobjetospuedenserusadosenlacreacióndeobjetostrait.Untraitesseguroparaobjetossiambascondicionessonverdaderas:

eltraitnorequierequeSelf:Sizedtodossusmétodossonsegurosparaobjetos

Entonces,quehaceaunmetodoseguroparaobjetos?CadametododeberequerirqueSelf:Sizedotodasdelassiguientes:

nodebetenerningunaparámetrodetiponodebeusarSelf

Uff!Comopodemosver,casitodasestasreglashablanacercadeSelf.Unabuenaintuiciónseria“exceptuandocircunstanciasespeciales,situmetododetraitusaSelf,noesseguroparaobjetos.”

ElLenguajedeProgramacionRust

246ObjetosTrait

Page 247: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Closures

Algunasvecesesutilenvolverunafunciónysusvariableslibresparamejorclaridadyreusabilidad.Lasvariableslibresquepuedenserusadasprovienendelámbitoexterioryson‘cerradas’(‘closedover’)cuandosonusadasenlafunción.Deallíelnombre‘closure’.Rustproveeunamuybuenaimplementación,comoveremosacontinuación.

SintaxisLosclosureslucenasí:

letsuma_uno=|x:i32|x+1;

assert_eq!(2,suma_uno(1));

Creamosunenlaceavariable,suma_unoyloasignamosaunclosure.Losargumentosdelclosurevanentrepipes(|),yelcuerpoesunaexpresión,enestecaso,x+1.Recuerdaque{}esunaexpresión,demaneraquepodemostenertambiénclosuresmulti-linea:

letsuma_dos=|x|{

letmutresultado:i32=x;

resultado+=1;

resultado+=1;

resultado

};

assert_eq!(4,suma_dos(2));

Notarasunpardecosasacercadelosclosuresquesonunpocodiferentesdelasfuncionesregularesdefinidasconfn.Loprimeroesquenonecesitamosanotarlostiposdelosargumentoslosvaloresderetorno.Podemos:

letsuma_uno=|x:i32|->i32{x+1};

assert_eq!(2,suma_uno(1));

Perononecesitamoshacerlo.Porque?Básicamente,seimplementodeesamaneraporrazonesdeergonomia.Sibienespecificareltipocompletoparafuncionesconnombreesdeutilidadparacosascomodocumentacióneinferenciadetipos,lafirmacompletaenlos

ElLenguajedeProgramacionRust

247Closures

Page 248: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

closuresesraramentedocumentadapuestoaquecasisiempresonanónimos,ynocausanlosproblemasdetipodeerror-a-distanciaquelainferenciaenfuncionesconnombrepuedencausar.

Lasegundasintaxisessimilar,perountantodiferente.Heagregadoespaciosacáparafacilitarlacomparación:

fnsuma_uno_v1(x:i32)->i32{x+1}

letsuma_uno_v2=|x:i32|->i32{x+1};

letsuma_uno_v3=|x:i32|x+1;

Pequenasdiferencias,perosonsimilares.

ClosuresysuentornoElentornoparaunclosurepuedeincluirenlacesavariabledelámbitoquelosenvuelveenadiciónalosparámetrosyvariableslocales.Deestamanera:

letnum=5;

letsuma_num=|x:i32|x+num;

assert_eq!(10,suma_num(5));

Elclosuresuma_num,hacereferenciaaelenlaceletensuámbito:num.Masespecíficamente,tomaprestadoelenlace.Sihacemosalgoqueresulteenunconflictocondichoenlace,obtendríamosunerrorcomoeste:

letmutnum=5;

letsuma_num=|x:i32|x+num;

lety=&mutnum;

Quefallacon:

ElLenguajedeProgramacionRust

248Closures

Page 249: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

error:cannotborrow`num`asmutablebecauseitisalsoborrowedasimmutable

lety=&mutnum;

^~~

note:previousborrowof`num`occurshereduetouseinclosure;theimmutable

borrowpreventssubsequentmovesormutableborrowsof`num`untiltheborrow

ends

letsuma_num=|x|x+num;

^~~~~~~~~~~

note:previousborrowendshere

fnmain(){

letmutnum=5;

letsuma_num=|x|x+num;

lety=&mutnum;

}

^

Unerroruntantoverboseperoigualdeutil!Comolodice,nopodemostomarunpréstamomutableennumdebidoaqueelclosureyaestatomándoloprestado.Sidejamoselclosurefueradeámbito,entoncesesposible:

letmutnum=5;

{

letsuma_num=|x:i32|x+num;

}//suma_numsaledeambito,elprestamoterminaaqui

lety=&mutnum;

Sinembargo,situclosureasílorequiere,Rusttomaraperteneciaymoveráelentorno.Losiguientenofunciona:

letnums=vec![1,2,3];

lettoma_nums=||nums;

println!("{:?}",nums);

Obtenemosesteerror:

note:`nums`movedintoclosureenvironmentherebecauseithastype

`[closure(())->collections::vec::Vec]`,whichisnon-copyable

lettoma_nums=||nums;

^~~~~~~

ElLenguajedeProgramacionRust

249Closures

Page 250: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Vec<T>poseeperteneciadesucontenido,yesporello,quealhacerreferenciaaeldentrodenuestroclosure,tenemosquetomarpertenenciadenums.Eslomismoquesihubiéramosproporcionadonumscomoargumentoaunafunciónquetomarapertenenciasobreel.

ClosuresmovePodemosforzarnuestroclosureatomarperteneciadesuentornoconlapalabrareservadamove:

letnum=5;

lettoma_pertenecia_num=move|x:i32|x+num;

Ahora,auncuandolapalabrareservadamoveestapresente,lasvariablessiguenlasemánticanormal.Enestecaso,5implementaCopy,yenconsecuencia,toma_pertenecia_numtomaperteneciadeunacopiadenum.Entonces,cualesladiferencia?

letmutnum=5;

{

letmutsuma_num=|x:i32|num+=x;

suma_num(5);

}

assert_eq!(10,num);

Enestecaso,nuestroclosuretomounareferenciamutableanum,ycuandollamamosasuma_num,estemutoelvalorsubyacente,talycomoloesperábamos.Tambiénnecesitamosdeclararsuma_numcomomut,puestoaqueestamosmutandosuentorno.

Silocambiamosaunclosuremove,esdiferente:

letmutnum=5;

{

letmutsuma_num=move|x:i32|num+=x;

suma_num(5);

}

assert_eq!(5,num);

ElLenguajedeProgramacionRust

250Closures

Page 251: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Obtenemossolo5.Enlugardetomarunprestamomutableennuestronum,tomamosperteneciasobreunacopia.

Otraformadepensaracercadelosclosuresmovees:estosproporcionanaelclosuresupropioregistrodeactivación.Sinmove,elclosurepuedeserasociadoaelregistrodeactivaciónquelocreo,mientrasqueunclosuremoveesautocontenido.Loquesignifica,porejemplo,quegeneralmentenopuedesretornarunclosureno-movedesdeunafunción.

Peroantesdehablarderecibirclosurescomoparámetrosyusarloscomovaloresderetorno,debemoshablarunpocomasacercadesuimplementación.ComounlenguajedeprogramacióndesistemasRustteproporcionaunatoneladadecontrolacercadeloquetucódigohace,ylosclosuresnosondiferentes.

ImplementacióndelosClosuresLaimplementacióndeclosuresdeRustesunpocodiferentealadeotroslenguajes.EnRust,losclosuressonefectivamenteunasintaxisalternaparalostraits.Antesdecontinuar,necesitarashaberleídoelcapitulodetraitsasicomoelcapituloacercadeobjetostrait.

Yaloshasleído?Excelente.

Laclaveparaentendercomofuncionanlosclosuresesalgounpocoextraño:Usar()parallamarunafunción,comofoo(),esunoperadorsobrecargable.Partiendodesdeestapremisa,todolodemásencaja.EnRusthacemosusodeelsistemadetraitsparasobrecargaroperadores.Llamarfuncionesnoesdiferente.Existentrestraitsquepodemossobrecargar:

#modfoo{

pubtraitFn<Args>:FnMut<Args>{

extern"rust-call"fncall(&self,args:Args)->Self::Output;

}

pubtraitFnMut<Args>:FnOnce<Args>{

extern"rust-call"fncall_mut(&mutself,args:Args)->Self::Output;

}

pubtraitFnOnce<Args>{

typeOutput;

extern"rust-call"fncall_once(self,args:Args)->Self::Output;

}

#}

ElLenguajedeProgramacionRust

251Closures

Page 252: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Notarasunaspocasdiferenciasentredichostraits,perounagrandeesself:Fnrecibe&self,FnMuttoma&mutselfyFnOncerecibeself.Loanteriorcubrelostrestiposdeselfatravésdelasintaxisusualdellamadasamétodos.Perohansidoseparadosentrestraits,enlugardeunosolo.Estonosproporcionagrancontrolacercadeltipodeclosuresquepodemosrecibir.

Lasintaxis||{}esunasintaxisalternaparaesostrestraits.Rustgeneraraunstructparaelentorno,impleltraitapropiado,yluegoharáusodeeste.

RecibiendoclosurescomoargumentosAhoraquesabemosquelosclosuressontraits,entoncessabemoscomoaceptaryretornarclosures:justocomocualquierotrotrait!

Loanteriortambiénsignificaquepodemoselegirentredespachoestáticoodinámico.Primero,creemosunafunciónquerecibaalgollamable,ejecuteunallamadasobreelyluegoretorneelresultado:

fnllamar_con_uno<F>(algun_closure:F)->i32

whereF:Fn(i32)->i32{

algun_closure(1)

}

letrespuesta=llamar_con_uno(|x|x+2);

assert_eq!(3,respuesta);

Pasamosnuestroclosure,|x|x+2,allamar_con_uno.llamar_con_unohaceloquesugiere:llamaelclosure,proporcionándole1comoargumento.

Examinemoslafirmadellamar_con_unoconmayordetalle:

fnllamar_con_uno<F>(algun_closure:F)->i32

#whereF:Fn(i32)->i32{

#algun_closure(1)}

Recibimosunparámetro,detipoF.Tambiénretornamosuni32.Estapartenoesinteresante.Lasiguienteloes:

#fnllamar_con_uno<F>(algun_closure:F)->i32

whereF:Fn(i32)->i32{

#algun_closure(1)}

ElLenguajedeProgramacionRust

252Closures

Page 253: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

DebidoaqueFnesuntrait,podemoslimitarnuestrogenéricoconel.Enestecaso,nuestroclosurerecibeuni32yretornauni32,esporelloqueellimitedegenéricosqueusamosesFn(i32)->i32.

Hayotropuntoclaveacá:debidoaqueestamoslimitandoungenéricoconuntrait,lallamadaseramonomorfizada,yenconsecuencia,estaremoshaciendodespachoestáticoenelclosure.Esoessupercool.Enmuchoslenguajes,losclosuressoninherentementeasignadosdesdeelmontículo,ycasisiempreinvolucrarandespachodinámico.EnRustpodemosasignarelentornodenuestrosclosuresdesdelapila,asícomodespacharlallamadademaneraestática.Estoocurreconbastantefrecuenciaconlositeradoresysusadaptadores,quienesrecibenclosurescomoargumentos.

Porsupuesto,sideseamosdespachodinámico,podemostenerlotambién.Unobjetotrait,comoesusual,manejaestecaso:

fnllamar_con_uno(algun_closure:&Fn(i32)->i32)->i32{

algun_closure(1)

}

letanswer=llamar_con_uno(&|x|x+2);

assert_eq!(3,answer);

Ahorarecibimosunobjetotrait,un&Fn.Ytenemosquehacerunareferenciaanuestroclosurecuandolopasemosallamar_con_uno,esporelloqueusamos&||.

ApuntadoresafunciónyclosuresUnapuntadorafunciónesunaespeciedeclosurequenoposeeentorno.Comoconsecuencia,podemospasarunapuntadorafunciónacualquierfunciónquerecibaunclosurecomoargumento:

ElLenguajedeProgramacionRust

253Closures

Page 254: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnllamar_con_uno(algun_closure:&Fn(i32)->i32)->i32{

algun_closure(1)

}

fnsuma_uno(i:i32)->i32{

i+1

}

letf=suma_uno;

letrespuesta=llamar_con_uno(&f);

assert_eq!(2,respuesta);

Enelejemploanteriornonecesitamoslavariableintermediafdemaneraestricta,elnombredelafuncióntambiénsirve:

letrespuesta=llamar_con_uno(&suma_uno);

RetornandoclosuresEsmuycomúnparacódigoconestilofuncionalelretornarclosuresendiversassituaciones.Siintentasretornarunclosure,podríasincurrirenunerror.Alprincipiopuedeparecerextraño,peromasadelanteloentenderemos.Probablementeintentaríasretornarunclosuredesdeunafuncióndeestamanera:

fnfactory()->(Fn(i32)->i32){

letnum=5;

|x|x+num

}

letf=factory();

letrespuesta=f(1);

assert_eq!(6,respuesta);

Loanteriorgeneraestoslargos,perorelacionadoserrores:

ElLenguajedeProgramacionRust

254Closures

Page 255: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

error:thetrait`core::marker::Sized`isnotimplementedforthetype

`core::ops::Fn(i32)->i32`[E0277]

fnfactory()->(Fn(i32)->i32){

^~~~~~~~~~~~~~~~

note:`core::ops::Fn(i32)->i32`doesnothaveaconstantsizeknownatcompile-time

fnfactory()->(Fn(i32)->i32){

^~~~~~~~~~~~~~~~

error:thetrait`core::marker::Sized`isnotimplementedforthetype`core::ops::Fn(i32)->i32`[E0277]

letf=factory();

^

note:`core::ops::Fn(i32)->i32`doesnothaveaconstantsizeknownatcompile-time

letf=factory();

^

Pararetornaralgodesdeunafunción,Rustnecesitasabereltamañodeltipoderetorno.PerodebidoqqueFnesuntrait,puedeservariascosasdediversostamaños:muchostipospuedenimplementarFn.Unamanerafácildedarletamañoaalgoestomandounareferenciaaeste,debidoaquelasreferenciastienenuntamañoconocido.Enlugardeloanteriorpodemosescribir:

fnfactory()->&(Fn(i32)->i32){

letnum=5;

|x|x+num

}

letf=factory();

letrespuesta=f(1);

assert_eq!(6,respuesta);

Peroobtenemosotroerror:

error:missinglifetimespecifier[E0106]

fnfactory()->&(Fn(i32)->i32){

^~~~~~~~~~~~~~~~~

Bien.Debidoaquetenemosunareferencia,necesitamosproporcionaruntiempodevida.peronuestrafunciónfactory()norecibeningunargumentoyporellolaelisiondetiemposdevidanoesposibleenestecaso.Entoncesqueopcionestenemos?Intentemoscon'static:

ElLenguajedeProgramacionRust

255Closures

Page 256: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

fnfactory()->&'static(Fn(i32)->i32){

letnum=5;

|x|x+num

}

letf=factory();

letrespuesta=f(1);

assert_eq!(6,respuesta);

Peroobtenemosotroerror:

error:mismatchedtypes:

expected`&'staticcore::ops::Fn(i32)->i32`,

found`[closure@:7:9:7:20]`

(expected&-ptr,

foundclosure)[E0308]

|x|x+num

^~~~~~~~~~~

Elerrornosdicequenotenemosun&'staticFn(i32)->i32,sinoun[closure@<anon>:7:9:7:20].Unmomento,que?

DebidoaquenuestroclosuregenerasupropiostructparaelentornoasícomounaimplementaciónparaFn,FnMutyFnOnce,dichostipossonanónimos.Soloexistenparaesteclosure.EsporelloqueRustlosmuestracomoclosure@<anon>envezdealgúnnombreautogenerado.

Elerrortambiénhabladequeseesperaqueeltipoderetornoseaunareferencia,peroloqueestamostratandoderetornarnoloes.Masaun,nopodemosasignardirectamenteuntiempodevida'static'aunobjeto.Entoncestomaremosunenfoquediferenteyretornaremosun‘traitobject’envolviendoelFnenunBox.Losiguientecasifunciona:

fnfactory()->Boxi32>{

letnum=5;

Box::new(|x|x+num)

}

#fnmain(){

letf=factory();

letrespuesta=f(1);

assert_eq!(6,respuesta);

#}

ElLenguajedeProgramacionRust

256Closures

Page 257: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Hayunultimoproblema:

error:closuremayoutlivethecurrentfunction,butitborrows`num`,

whichisownedbythecurrentfunction[E0373]

Box::new(|x|x+num)

^~~~~~~~~~~

Bueno,comodiscutimosanteriormente,losclosurestomansuentornoprestado.Yenestecaso,nuestroentornoestabasadoenun5asignadodesdelapila,lavariablenum.Debidoaestoelprestamoposeeeltiempodevidadelregistrodeactivación.Deretornaresteclosure,lallamadaafunciónpodríaterminar,elregistrodeactivacióndesapareceríaynuestroclosureestaríacapturandounentornodememoriabasura!Conunultimoarreglo,podemoshacerquefuncione:

fnfactory()->Box<Fn(i32)->i32>{

letnum=5;

Box::new(move|x|x+num)

}

#fnmain(){

letf=factory();

letrespuesta=f(1);

assert_eq!(6,respuesta);

#}

AlhacerelclosureinternounmoveFn,hemoscreadounnuevoregistrodeactivaciónparanuestroclosure.EnvolviéndoloconunBox,lehemosproporcionadountamañoconocido,permitiéndoleescaparnuestroregistrodeactivación.

ElLenguajedeProgramacionRust

257Closures

Page 258: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%SintaxisUniversaldeLlamadasaFunción

Algunasveces,variasfuncionespuedentenerelmismonombre.Consideraelsiguientecódigo:

traitFoo{

fnf(&self);

}

traitBar{

fnf(&self);

}

structBaz;

implFooforBaz{

fnf(&self){println!("impldeFooenBaz");}

}

implBarforBaz{

fnf(&self){println!("impldeBarenBaz");}

}

letb=Baz;

Siintentaramosllamarb.f(),obtendriamosunerror:

error:multipleapplicablemethodsinscope[E0034]

b.f();

^~~

note:candidate#1isdefinedinanimplofthetrait`main::Foo`forthetype

`main::Baz`

fnf(&self){println!("Baz’simplofFoo");}

^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

note:candidate#2isdefinedinanimplofthetrait`main::Bar`forthetype

`main::Baz`

fnf(&self){println!("Baz’simplofBar");}

^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Necesitamosunaformadeeliminarlaambigüedad.Estacaracterísticaesdenominada‘sintaxisuniversaldellamadasafunción’,yluceasí:

ElLenguajedeProgramacionRust

258SintaxisUniversaldeLlamadaaFunciones

Page 259: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#traitFoo{

#fnf(&self);

#}

#traitBar{

#fnf(&self);

#}

#structBaz;

#implFooforBaz{

#fnf(&self){println!("impldeFooenBaz");}

#}

#implBarforBaz{

#fnf(&self){println!("impldeBarenBaz");}

#}

#letb=Baz;

Foo::f(&b);

Bar::f(&b);

Analicémosloporpartes.

Foo::

Bar::

Dichasmitadesdeinvocacionsonlostiposdelostraits:FooyBar.Loanterioresresponsabledelaeliminacióndelaambigüedadentrelasdosllamadas:Rustllamalafuncióndeltraitquenombraste.

f(&b)

Cuandollamamosunmétododelaformab.f()usandolasintaxisdemétodos,Rustautomáticamentetomaraprestadoabsif()recibea&self.Enestecaso,Rustnopuedehacerlo.Esporelloquedebemospasara&bdemaneraexplicita.

Usando<>LaformadeSULFdelaqueacabamosdehablar:

Trait::metodo(args);

Esunaversioncorta.Existeunaversionexpandidaquepuedesernecesariaenalgunassituaciones:

::metodo(args);

ElLenguajedeProgramacionRust

259SintaxisUniversaldeLlamadaaFunciones

Page 260: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Lasintaxis<>::esunaformadeproporcionarunapistadetipos.Eltipovadentrodelos<>s.EnestecasoesTypeasTraitindicandoquedeseamosllamaralaversionTraitdemetodo.LasecciónasTraitesopcionaldenoserambigua.Lomismoconlos<>s,deallíprovieneversionmascorta.

Acáunejemplodelusodelaformamaslarga.

traitFoo{

fnclone(&self);

}

#[derive(Clone)]

structBar;

implFooforBar{

fnclone(&self){

println!("CreandounclondeBar");

<BarasClone>::clone(self);

}

}

LoanteriorllamaraelmetodocloneeneltraitClone,envezdelaversionclonedeltraitFoo.

ElLenguajedeProgramacionRust

260SintaxisUniversaldeLlamadaaFunciones

Page 261: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%CratesyModulos

Cuandounproyectocomienzaacrecer,seconsiderabuenapracticadeingenieríadesoftwaredividirloenungrupodecomponentesmaspequeñosqueposteriormenteseránunidos.Tambiénesimportantetenerunainterfazbiendefinida,demaneraqueunapartedelafuncionalidadseaprivada,yotrapublica.Parafacilitaresto,Rustposeeunsistemademódulos.

Terminologiabasica:CratesyModulosRustposeedostérminosdistintosrelacionadosconelsistemademódulos:‘crate’y‘modulo’.Uncrateesunsinónimopara‘biblioteca’or‘paquete’enotroslenguajes.Deallíelnombre“Cargo”delmanejadordepaquetesdeRust:hacesdisponiblestuscratesalosdemásconCargo.Loscratespuedenproducirunejecutablesounabiblioteca,dependiendodelproyecto.

Cadacrateposeeunmoduloraizimplícitoquecontieneelcódigoparadichocrate.Puedesdefinirunárboldesub-modulosbajoelmóduloraíz.Losmódulostepermitenparticionartucodigodentrodelcrate.

Comoejemplo,creemosuncratefrases,quenosproveerávariasfrasesendiferentesidiomas.Paramantenerlascosassimples,nosapegaremossoloa‘saludos’y‘despedidas’comolosdostiposdefrases,asícomoInglesyJaponés(日本語)paralosdosidiomasenlosquelasfrasesestaránrepresentadas.Tendremoslasiguientedistribucióndemódulos:

+-----------+

+---|saludos|

|+-----------+

+----------+|

+---|ingles|---+

|+----------+|+-----------+

|+---|despedidas|

+----------+|+-----------+

|frases|---+

+----------+|+-----------+

|+---|saludos|

|+-----------+|+-----------+

+---|japonés|--+

+-----------+|

|+------------+

+---|despedidas|

+------------+

ElLenguajedeProgramacionRust

261CratesyMódulos

Page 262: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Enesteejemplo,fraseseselnombredenuestrocrate.Elrestosonmódulos.Puedesobservarquelosmódulosformanunárbol,partiendodesdelaraíz,queasuvezeslaraízdelárbolfrasesensi.

Ahoraquetenemosunplan,definamosestosmódulosencódigo.Paracomenzar,generemosunproyectoconCargo:

$cargonewfrases

$cdfrases

Sirecuerdas,loanteriorgeneraunproyectosimple:

$tree.

.

├──Cargo.toml

└──src

└──lib.rs

1directory,2files

src/lib.rseslaraízdenuestrocrate,correspondiendoconfrasesennuestrodiagramaanterior.above.

DefiniendoMódulosParadefinircadaunodenuestrosmódulos,usamoslapalabrareservadamod.Hagamosquenuestrosrc/lib.rsseveaasí:

modingles{

modsaludos{

}

moddespedidas{

}

}

modjapones{

modsaludos{

}

moddespedidas{

}

}

ElLenguajedeProgramacionRust

262CratesyMódulos

Page 263: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Despuésdelapalabrareservadamoddebesproporcionarelnombredelmodulo.LosnombresdedemodulosiguenlasmismasconvencionesquelosdemásidentificadoresenRust:snake_case_en_minusculas.Elcontenidodecadamoduloestadelimitadoporllaves({}).

Dentrodeundeterminadomod,puedesdeclararsub-mods.Podemosreferirnosalossub-modulosconunanotacióndospuntosdobles(::):nuestroscuatromódulosanidadossoningles::saludos,ingles::despedidas,japones::saludos,yjapones::despedidas.Debidoaqueestossub-modulosestándentrodelespaciodenombresdelmodulopadre,losnombresnoentranenconflicto:ingles::saludosyjapones::saludossondistintosinclusocuandosusnombressonambossaludos.

Debidoaqueestecratenoposeeunafunciónmain(),ysellamalib.rs,Cargoconstruiráestecratecomounabiblioteca:

$cargobuild

Compilingfrasesv0.0.1(file:///home/tu/proyectos/frases)

$lstarget/debug

builddepsexampleslibfrases-a7448e02a0468eaa.rlibnative

libfrases-hash.rlibeselcratecompilado.Antesdevercomousarestecratedesdeotro,dividámosloenmultiplesarchivos.

CratesconmultiplearchivosSicadacratefueraunsoloarchivo,dichosarchivosserianbastantegrandes.Esmasfácildividirloscratesenmultiplesarchivos.Rustsoportaestodedosmaneras.

Enlugardedeclararunmoduloasí:

modingles{

//elcontenidodelmodulovaaquí

}

Podemosdeclararlodeestaforma:

modingles;

Sihacemoseso,Rustesperaraencontrarbienunarchivoingles.rsounarchivoingles/mod.rsconelcontenidodenuestromodulo.

ElLenguajedeProgramacionRust

263CratesyMódulos

Page 264: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Notaquetodosenestosarchivos,nonecesitasre-declararelmodulo:conladeclaracióninicialmodessuficiente.

Usandoestasdostécnicas,podemospartirnuestrocrateendosdirectoriosysietearchivos:

$tree.

.

├──Cargo.lock

├──Cargo.toml

├──src

│├──ingles

││├──despedidas.rs

││├──saludos.rs

││└──mod.rs

│├──japones

││├──despedidas.rs

││├──saludos.rs

││└──mod.rs

│└──lib.rs

└──target

└──debug

├──build

├──deps

├──examples

├──libfrases-a7448e02a0468eaa.rlib

└──native

src/lib.rseslaraízdenuestrocrate,yluceasí:

modingles;

modjapones;

EstasdosdeclaracionesledicenaRustquebusquebienseasrc/ingles.rsysrc/japones.rs,osrc/ingles/mod.rsysrc/japones/mod.rs,dependiendodenuestrapreferencia.Enestecaso,debidoaquenuestrosmódulosposeensub-moduloshemosseleccionadolasegunda.Ambossrc/ingles/mod.rsysrc/japones/mod.rssevenlucendeestamanera:

modsaludos;

moddespedidas;

Denuevo,estasdeclaracioneshacenqueRustbusquebienseaporsrc/ingles/saludos.rsysrc/japones/saludos.rsosrc/ingles/despedidas/mod.rsandsrc/japones/despedidas/mod.rs.Debidoaquelossub-modulosnoposeensuspropiossub-

ElLenguajedeProgramacionRust

264CratesyMódulos

Page 265: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

modulos,hemosoptadoporusarelenfoquesrc/ingles/saludos.rsandsrc/japones/despedidas.rs.Uff!

Ambossrc/ingles/saludos.rsysrc/japones/despedidas.rsestánvacíosporelmomento.Agreguemosalgunasfunciones.

Colocaestoensrc/ingles/saludos.rs:

fnhola()->String{

"Hello!".to_string()

}

Putthisinsrc/ingles/despedidas.rs:

fnadios()->String{

"Goodbye.".to_string()

}

Putthisinsrc/japones/saludos.rs:

fnhello()->String{

"こんにちは".to_string()

}

Porsupuesto,puedescopiarypegarelJaponesdesdeestapaginaweb,osimplementeescribealgunaotracosa.Noesimportantequeenefectocoloques‘konnichiwa’paraaprenderacercadelsistemademódulosdeRust.

Colocalosiguienteensrc/japones/despedidas.rs:

fnadios()->String{

"さようなら".to_string()

}

(‘Sayōnara’,porsierescurioso.)

Ahoraquetenemosalgodefuncionalidadennuestrocrate,intentemosusarlosdesdeotro.

ImportingExternalCratesYatenemosuncratebiblioteca.Creemosuncrateejecutablequeimporteyusenuestrabiblioteca.

ElLenguajedeProgramacionRust

265CratesyMódulos

Page 266: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Creaunarchivosrc/main.rsycolocaestoenel(nocompilaratodavía):

externcratefrases;

fnmain(){

println!("HolaenIngles:{}",frases::ingles::saludos::hola());

println!("AdiosenIngles:{}",frases::ingles::despedidas::adios());

println!("HolaenJapones:{}",frases::japones::saludos::hola());

println!("AdiosenJapones:{}",frases::japones::despedidas::adios());

}

LadeclaraciónexterncrateleinformaaRustquenecesitamoscompilaryenlazaralcratefrases.Podemosentoncesusarelmodulofrasesaqui.Comomencionamosanteriormente,puedeshacerusodedospuntosdoblesparahacerreferenciaalossub-modulosylasfuncionesdentrodeellos.

Nota:cuandoseimportauncratequetieneguionesensunombre"como-este",locualnoesunidentificadorvalidoenRust,seraconvertidocambiándolelosguionesaguionesbajos,asíqueescribiríasalgocomoexterncratecomo_este;

También,Cargoassumequesrc/main.rseslaraízdeuncratebinario,enlugardeuncratebiblioteca.Nuestropaqueteahoratienedoscrate:src/lib.rsysrc/main.rs.Estepatronesmuycomúnencratesejecutables:lamayoríadelafuncionalidadestaenuncratebiblioteca,yelcrateejecutableusadichabiblioteca.Deestaforma,otrosprogramaspuedentambiénhacerusodelabiblioteca,aunadoaqueofreceunbuenaseparaciónderesponsabilidades.

Loanteriortodavíanofunciona.Obtenemoscuatroerroresquelucensimilaresaestos:

$cargobuild

Compilingfrasesv0.0.1(file:///home/tu/proyectos/frases)

src/main.rs:4:38:4:72error:function`hola`isprivate

src/main.rs:4println!("HolaenIngles:{}",frases::ingles::saludos::hola());

^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

note:inexpansionofformat_args!

<stdmacros>:2:25:2:58note:expansionsite

<stdmacros>:1:1:2:62note:inexpansionofprint!

<stdmacros>:3:1:3:54note:expansionsite

<stdmacros>:1:1:3:58note:inexpansionofprintln!

frases/src/main.rs:4:5:4:76note:expansionsite

PordefectotodoesprivadoenRust.Hablemosdeestoconmayordetalle.

ExportandounaInterfazPublica

ElLenguajedeProgramacionRust

266CratesyMódulos

Page 267: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Rusttepermitecontrolardemaneraprecisacualesaspectosdetuinterfazsonpúblicos,yprivateeseldefacto.Parahaceraalgopublico,debeshacerusodelapalabrareservadapub.Enfoquemonosprimeroenelmoduloingles,paraello,reduzcamosnuestrosrc/main.rsa:

externcratefrases;

fnmain(){

println!("HolaenIngles:{}",frases::ingles::saludos::hola());

println!("AdiosenIngles:{}",frases::ingles::despedidas::adios());

}

Ennuestrosrc/lib.rs,agreguemospubaladeclaracióndelmoduloingles:

pubmodingles;

modjapones;

Yennuestrosrc/ingles/mod.rs,hagamosaambospub:

pubmodsaludos;

pubmoddespedidas;

Ennuestrosrc/ingles/saludos.rs,agreguemospubanuestradeclaraciónfn:

pubfnhola()->String{

"Hola!".to_string()

}

Ytambiénensrc/ingles/despedidas.rs:

pubfnadios()->String{

"Adios.".to_string()

}

Ahora,nuestrocratecompila,conunaspocasadvertenciasacercadenohaberusadolasfuncionesenjapones:

ElLenguajedeProgramacionRust

267CratesyMódulos

Page 268: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$cargorun

Compilingfrasesv0.0.1(file:///home/tu/proyectos/frases)

src/japones/saludos.rs:1:1:3:2warning:functionisneverused:`hola`,#[warn(dead_code)]onbydefault

src/japones/saludos.rs:1fnhola()->String{

src/japones/saludos.rs:2"こんにちは".to_string()

src/japones/saludos.rs:3}

src/japones/despedidas.rs:1:1:3:2warning:functionisneverused:`adios`,#[warn(dead_code)]onbydefault

src/japones/despedidas.rs:1fnadios()->String{

src/japones/despedidas.rs:2"さようなら".to_string()

src/japones/despedidas.rs:3}

Running`target/debug/frases`

HolaenIngles:Hello!

AdiosenIngles:Goodbye.

pubtambiénaplicaalasstructsysuscamposmiembro.YRustteniendosiempresutendenciahacialaseguridad,elhacerunastructpublicnoharáasusmiembrospublicautomáticamente:debesmarcarlosindividualmentecomopub.

Ahoraquenuestrasfuncionessonpublic,podemoshacerusodeellas.Grandioso!Sinembargo,escribirfrases::ingles::saludos::hola()eslargoyrepetitivo.Rustposeeotrapalabrareservadaparaimportarnombresenelámbitoactual,demaneraquepuedashacerreferenciaaellosconnombresmascortos,Hablemosacercadeuse.

ImportandoModuloscon useRustposeeunapalabrareservada,use,quetepermiteimportarnombresentuámbitolocal.Cambiemosnuestrosrc/main.rsparaqueluzcadelasiguientemanera:

externcratefrases;

usefrases::ingles::saludos;

usefrases::ingles::despedidas;

fnmain(){

println!("HolaenIngles:{}",saludos::hola());

println!("AdiosenIngles:{}",despedidas::adios());

}

Lasdoslineasuseimportancadamoduloenelámbitolocal,demaneratalquepodamosreferirnosalasfuncionesconnombresmuchomascortos.Porconvención,cuandoseimportanfunciones,seconsideraunabuenapracticaimportarelmodulo,enlugardelafuncióndirectamente.Enotraspalabras,puedeshaceresto:

ElLenguajedeProgramacionRust

268CratesyMódulos

Page 269: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

externcratefrases;

usefrases::ingles::saludos::hola;

usefrases::ingles::despedidas::adios;

fnmain(){

println!("HolaenIngles:{}",hola());

println!("AdiosenIngles:{}",adios());

}

Peronoesidiomático.Hacerlodeestaformatienealtasprobabilidadesdeintroducirunconflictodenombres.Ennuestropequeñoprograma,noesgrancosa,peroamedidaquecrece,sevaconvirtiendoenunproblema.Sitenemosnombresconflictivos,Rustgeneraraunerrordecompilación.Porejemplo,dehaberhechopublicaslasfuncionesdejaponesyhaberintentado:

externcratefrases;

usefrases::ingles::saludos::hola;

usefrases::japones::saludos::hola;

fnmain(){

println!("HolaenIngles:{}",hola());

println!("HolaenJapones:{}",hola());

}

Rustproporcionaríaunerrorentiempodecompilación:

Compilingfrasesv0.0.1(file:///home/tu/frases)

src/main.rs:4:5:4:40error:avaluenamed`hola`hasalreadybeenimportedinthismodule[E0252]

src/main.rs:4usefrases::japones::saludos::hola;

^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error:abortingduetopreviouserror

Couldnotcompile`frases`.

Siestuviéramosimportandomultiplesnombresdelmismomodulo,nonecesitamosescribirlodosveces.Enlugarde:

usephrases::ingles::saludos;

usephrases::ingles::despedidas;

Podemosusarestaversionmascorta:

ElLenguajedeProgramacionRust

269CratesyMódulos

Page 270: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usephrases::ingles::{saludos,despedidas};

Re-exportandoconpubuseNosolousamosuseparaacortaridentificadores.Puedestambiénusarlosdentrodetucrateparare-exportarunafuncióndentrodeotromodulo.Estotepermitepresentarunainterfazexternaquenecesariamentenomapeededirectamentealaorganizacióninternadetucódigo.

Veamosunejemplo.modificatusrc/main.rsparaqueseleaasí:

externcratefrases;

usefrases::ingles::{saludos,despedidas};

usefrases::japones;

fnmain(){

println!("HolaenIngles:{}",saludos::hola());

println!("AdiosenIngles:{}",despedidas::adios());

println!("HolaenJapones:{}",japones::hola());

println!("AdiosenJapones:{}",japones::adios());

}

Entonces,modificatusrc/lib.rsparahacerelmodulojaponespublico:

pubmodingles;

pubmodjapones;

Acontinuación,hazlasdosfuncionespublicas,primeroensrc/japones/saludos.rs:

pubfnhola()->String{

"こんにちは".to_string()

}

Yluegoensrc/japones/despedidas.rs:

pubfnadios()->String{

"さようなら".to_string()

}

Finalmente,modificatusrc/japones/mod.rsdeestaforma:

ElLenguajedeProgramacionRust

270CratesyMódulos

Page 271: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

pubuseself::saludos::hola;

pubuseself::despedidas::adios;

modsaludos;

moddespedidas;

Ladeclaraciónpubusetraelafunciónaelámbitoenestapartedenuestrajerarquíademodulos.Debidoquehemoshechopubusedentrodenuestromodulojapones,ahoratenemosunafunciónfrases::japones::hola()yunafunciónfrases::japones::adios(),auncuandoelcódigoparaellasviveenfrases::japones::saludos::hola()yfrases::japones::despedidas::adios()`.Nuestraorganizacióninternanodefinenuestrainterfazexterna.

Acátenemosunpubuseparacadafunciónquedeseamostraerenelámbitodejapones.Alternativamentepudimoshaberusadolasintaxisalternativadecomodínparaincluirtododesdesaludosenelámbitoactual:pubuseself::saludos::*

Quehayacercadeelself?Bueno,pordefecto,lasdeclaracionesusesonrutasabsolutas,partiendodesdelaraízdetucrate.self,adiferencia,haceesarutarelativaatulugaractualdentrodelajerarquía.Hayunaultimaformaespecialdeusaruse:puedesusarusesuper::paraalcanzarunnivelsuperiorenlajerarquíadesdetuposiciónactual.Algunaspersonasgustanveraselfcomo.ysupercomo..similarmentelosusadosporlosshellsparamostrarlosdirectoriosactualypadrerespectivamente.

Fueradeuse,lasrutassonrelativas:foo::bar()serefiereaunafuncióndentrodefooenrelaciónaendondeestamos.Siposeeunprefijo::,comoen::foo::bar(),entoncesserefiereaunfoodiferente,unarutaabsolutadesdelaraízdetucrate.

Elultimocódigoqueescribimos,compilarayseejecutarasinproblemas:

$cargorun

Compilingfrasesv0.0.1(file:///home/tu/proyectos/frases)

Running`target/debug/frases`

HolainIngles:Hello!

AdiosinIngles:Goodbye.

HolainJapones:こんにちは

AdiosinJapones:さようなら

ImportescomplejosRustofreceunnumerodeopcionesavanzadasquepuedenhacertussentenciasexterncratemascompactasyconvenientes.Heaquíunejemplo:

ElLenguajedeProgramacionRust

271CratesyMódulos

Page 272: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

externcratefrasesasdichos;

usedichos::japones::saludosassaludos_ja;

usedichos::japones::despedidas::*;

usedichos::ingles::{self,saludosassaludos_en,despedidasasdespedidas_en};

fnmain(){

println!("HolaenIngles;{}",saludos_en::hola());

println!("YenJapones:{}",saludos_ja::hola());

println!("GoodbyeinIngles:{}",ingles::despedidas::adios());

println!("Otravez:{}",despedidas_en::adios());

println!("YenJapones:{}",adios());

}

Queestapasando?

Primero,ambosexterncrateyusepermitenrenombrarloqueestasiendoimportado.Entonceselcratetodavíasellama"frases",peroaquínosreferiremosaelcomo"dichos".Similarmente,elprimerusetraeelmodulojapones::saludosdesdeelcrate,perolohacedisponibleatravésdelnombresaludos_jaenlugardesimplementesaludos.Loanteriorpuedeayudaraevitarambigüedadcuandoseimportannombressimilaresdesdedistintoslugares.

Elsegundouseposeeunasteriscoparatraertodoslossímbolosdesdeelmodulodichos::japones::despedidas.ComopodrásvermastardepodemosreferirnosaladiosJaponessincalificadoresdemodulo.Estetipodeglobdebeserusandoconcautela.

Elterceruserequiereunpocomasdeexplicación.Estausando"expansiondellaves"paracomprimirtressentenciasuseenuna(estetipodesintaxispuedesertefamiliarsihasescritoscriptsdelshelldeLinux).Laformadescomprimidadeestasentenciaseria:

usedichos::ingles;

usedichos::ingles::saludosassaludos_en;

usedichos::ingles::despedidasasdespedidas_en;

Comopuedesver,lasllavescomprimenlassentenciasuseparavariositemsbajolamismaruta,yenestecontextoselfhacereferenciaadicharuta.Nota:Lasllavesnopuedenseranidadasomezcladasconglobbingdeasteriscos.

ElLenguajedeProgramacionRust

272CratesyMódulos

Page 273: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%constystatic

Rustposeeunamaneradedefinirconstantesconlapalabrareservadaconst:

constN:i32=5;

Adiferenciadelosenlacesavariablelet,debesanotareltipodeunconst.

Lasconstantesvivenporeltiempodevidacompletodelprograma.Parasermasespecíficos,lasconstantesenRustnotienendireccionesdememoriafijas.Estoesdebidoaqueestassoninsertadasenlineaencadalugarenelquesonusadas.Porestarazón,referenciasalamismaconstantenoestángarantizadasaapuntaralamismadireccióndememoria.

static

Rustproporcionaunafacilidaddetipo‘variableglobal’enitemsestáticos.Sonsimilaresalasconstantes,perolositemsestáticosnosoninsertadosenlineatrassuuso.Estosignificaquesoloexisteunainstanciaparacadavalor,yestaubicadaenunadireccióndememoriafija.

Heaquiunejemplo:

staticN:i32=5;

Adiferenciadelosenlacesavariablelet,debesanotareltipodeunstatic.

Lositemsstaticvivenporeltiempodevidadelprogramacompleto,yenconsecuenciacualquierreferenciaesalmacenadaenunaconstanteposeeuntiempodevida'static:

staticNOMBRE:&'staticstr="Steve";

MutabilidadPuedesintroducirmutabilidadconlapalabrareservadamut:

staticmutN:i32=5;

ElLenguajedeProgramacionRust

273`const`y`static`

Page 274: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Debidoqueesmutable,unhilopodríaestaractualizandoNmientrasqueotroesteleyéndolo,causandoinseguridadenelmanejodememoria.Esporelloqueamboselaccesoylamutacióndeunstaticmutsoninseguros,yenconsecuenciadebenserefectuadosdentrodeunbloqueunsafe:

#staticmutN:i32=5;

unsafe{

N+=1;

println!("N:{}",N);

}

Aunadoaesto,cualquiertipoalmacenadoenunstaticdebeserSync,ypodríanotenerunaimplementacióndeDrop.

InicializaciónAmbosconstystatictienenrequerimientosalproporcionarlesunvalor.Soloselespuedeproporcionarunvalorqueseaunaexpresiónconstante.Enotraspalabras,nopuedesusarelresultadodeunallamadaafunción,algosimilarmentecomplejooalgodeterminadoentiempodeejecución.

Cualconstruccióndeberíausar?Casisiempre,sipuedesescogerentrelasdos,eligeconst.Esbastanteraroquequierastenerunadireccióndememoriaasociadacontuconstante,también,elusarconstpermiteoptimizacionescomopropagacióndeconstantesnosoloentucratesinoenloscratessubyacentes.

ElLenguajedeProgramacionRust

274`const`y`static`

Page 275: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Atributos

Lasdeclaracionespuedenseranotadascon‘atributos’enRust.Losatributoslucenasí:

#[test]

#fnfoo(){}

odeestamanera:

#modfoo{

#![test]

#}

Ladiferenciaentrelosdosesel!,quecambiaaquecosaaplicaelatributo:

#[foo]

structFoo;

modbar{

#![bar]

}

Elatributo#[foo]aplicaaelsiguienteitem,queesladeclaracióndelstruct.Elatributo#![bar]aplicaaelitemqueloencierra,ladeclaraciónmod.Deresto,sonlomismo.Amboscambiandealgunaformaelsignificadodeelitemalcualestánasociados.

Porejemplo,consideraunafuncióncomoesta:

#[test]

fncomprobar(){

assert_eq!(2,1+1);

}

Estamarcadocon#[test].Estosignificaqueesespecial:cuandoejecuteslaspruebas,estafunciónseraejecutada.Cuandocompilasnormalmente,noseraincluidanisiquiera.Lafunciónesahoraunafuncióndeprueba.

Losatributospuedentenertambiéndataadicional:

#[inline(always)]

fnfn_super_rapida(){

#}

Oinclusoclavesyvalores:

ElLenguajedeProgramacionRust

275Atributos

Page 276: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#[cfg(target_os="macos")]

modsolo_macos{

#}

LosatributossonusadosparaunnumerodecosasdiferentesenRust.Hayunalistadeatributoscompletaenlareferencia.Actualmente,notienespermitidocreartuspropiosatributos,elcompiladordeRustlosdefine.

ElLenguajedeProgramacionRust

276Atributos

Page 277: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Aliastype

Lapalabrareservadatypetepermitedeclararunaliasaotrotipo:

typeNombre=String;

Ahora,puedesusarestetipocomosifuerauntiporeal:

typeName=String;

letx:Nombre="Hola".to_string();

Sinembargo,nota,queesunalias,nounnuevotipo.Enotraspalabras,debidoaqueRustesfuertementetipificado,podríasesperarqueunacomparaciónentredostiposdiferentesfalle:

letx:i32=5;

lety:i64=5;

ifx==y{

//...

}

loanterior,produce:

error:mismatchedtypes:

expected`i32`,

found`i64`

(expectedi32,

foundi64)[E0308]

ifx==y{

^

Pero,situviéramosunalias:

typeNum=i32;

letx:i32=5;

lety:Num=5;

ifx==y{

//...

}

ElLenguajedeProgramacionRust

277Alias`type`

Page 278: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Compilaríasinerrores.ValoresdeuntipoNumsonlomismoqueunvalordetipoi32,entodoslosaspectos.

Puedestambiénhacerusodealiasdetiposengenéricos:

usestd::result;

enumErrorConcreto{

Foo,

Bar,

}

typeResult<T>=result::Result<T,ErrorConcreto>;

Elcódigoanterior,creaunaversionespecializadadeeltipoResult,lacualposeesiempreunErrorConcretoparalaparteEdeResult<T,E>.Estapracticaesusadacomúnmenteenlabibliotecaestándarparalacreacióndeerrorespersonalizadosparacadasub-seccion.Porejemplo,io::Result.

ElLenguajedeProgramacionRust

278Alias`type`

Page 279: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%ConversiónEntreTipos

Rust,consufocoenseguridad,proporcionadosformasdiferentesdeconversiónentretipos.Laprimera,as,esparaconversiónsegura.Encontraste,transmutepermiteconversionarbitraria,yesunadelascaracterísticasmaspeligrosasdeRust!

as

Lapalabrareservadaasllevaacaboconversionbásica:

letx:i32=5;

lety=xasi64;

as,sinembargo,solopermiteciertostiposdeconversión:

leta=[0u8,0u8,0u8,0u8];

letb=aasu32;//cuatroochoshacen32

Loanteriorproduceunerror:

error:non-scalarcast:`[u8;4]`as`u32`

letb=aasu32;//cuatroochoshacen32

^~~~~~~~

Esuna‘conversionnoescalar’(‘non-scalarcast’)porquetenemosmultiplesvalores:loscuatroelementosenelarreglo.Estetipodeconversionessonmuypeligrosas,debidoaqueasumencosasacercadecomolasmultiplesestructurassubyacentesestánimplementadas.Paraesto,necesitamosalgomaspeligroso.

transmute

Lafuncióntransmuteesproporcionadaporunaintrínsecadelcompilador,yloquehaceesmuysimple,peroalmismotiempomuypeligroso.LediceaRustquetrateunvalordeuntipocomosifueraunvalordeotrotipo.Llevaacaboestosinrespetarelsistemadetipos,yconfíacompletamenteenti.

ElLenguajedeProgramacionRust

279ConversiónentreTipos

Page 280: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Ennuestroejemploanterior,sabemosquenuestroarreglodecuatrou8srepresentaunu32demaneracorrecta,porlotantoqueremoshacerlaconversión.UsandotransmuteenlugardeasRustnospermite:

usestd::mem;

unsafe{

leta=[0u8,0u8,0u8,0u8];

letb=mem::transmute::<[u8;4],u32>(a);

}

Debemosenvolverlaoperaciónenunbloqueunsafeparaqueelcódigoanteriorcompilesatisfactoriamente.Técnicamente,sololallamadaamem::transmutenecesitaestardentrodelbloque,peroenestecasoestabientenertodolorelacionadoalaconversiondemaneraquesepasendondebuscar.Enestecaso,losdetallesacercadeasontambiénimportantes,esporelloqueestándentrodelbloque.Verascódigoencualquieradelosdosestilos,algunasveceselcontextoestatanlejosqueenvolvertodoelcódigoenunbloqueunsafenoesunagranidea.

Mientrasquetransmutehacemuypocoschequeos,seasegura,almenos,quelostiposseandelmismotamaño.Losiguiente,falla:

usestd::mem;

unsafe{

leta=[0u8,0u8,0u8,0u8];

letb=mem::transmute::<[u8;4],=""u64="">(a);

}

con:

error:transmutecalledontypeswithdifferentsizes:[u8;4](32bits)tou64

(64bits)

Dichoesto,estásportucuenta!

ElLenguajedeProgramacionRust

280ConversiónentreTipos

Page 281: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%TiposAsociados

LostiposasociadossonunapartepoderosadelsistemadetiposdeRust.Serelacionanconlaideadeuna‘familiadetipos’,enotraspalabras,laagrupacióndemultiplestipos.Esadescripciónesunapocoabstracta,esmejorquenosadentremosdeunavezenunejemplo.SiqueremosescribiruntraitGrafo,tenemosdostiposporencimadeloscualesdebemossergenéricos:eltipodelosnodosyeltipodelosvertices.Podríamosescribiruntrait,Grafo<N,V>comoeste:

traitGrafo<N,V>{

fntiene_vertice(&self,&N,&N)->bool;

fnvertices(&self,&N)->Vec<V>;

//etc

}

Sibienestodealgunamanerafunciona,terminasiendounpocoraro.Porejemplo,cualquierfunciónquequierarecibirunGrafocomoparámetroahoratambiénnecesitasergenéricaporsobrelostiposNodoyVertice:

fndistancia>(grafo:&G,inicio:&N,fin:&N)->u32{...}

NuestrocalculodeladistanciafuncionasintomarencuentanuestrotipoVértice,enconsecuencialaVenestafirmaessimplementeunadistracción.

LoquerealmentequeremosexpresaresqueciertostiposVerticeyNodovienenjuntosparaformarcadaclasedeGrafo.Podemoshacerestocontiposasociados:

traitGrafo{

typeN;

typeV;

fntiene_vertice(&self,&Self::N,&Self::N)->bool;

fnvertices(&self,&Self::N)->Vec<Self::V>;

//etc

}

Ahora,nuestrosclientespuedenabstraerseporencimadeundeterminadoGrafo:

fndistancia(grafo:&G,inicio:&G::N,fin:&G::N)->u32{...}

SinnecesidaddelidiarconeltipoVertice!

Echemosunvistazoconmayordetalleatodoesto.

ElLenguajedeProgramacionRust

281TiposAsociados

Page 282: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

DefiniendotiposasociadosConstruyamosesetraitGrafo.Heaquíladefinición:

traitGraph{

typeN;

typeV;

fntiene_vertice(&self,&Self::N,&Self::N)->bool;

fnvertices(&self,&Self::N)->Vec<Self::V>;

}

Simple.Lostiposasociadosusanlapalabrareservadatype,yvandentrodelcuerpodeltraitenconjuntoconlasfunciones.

Dichasdeclaracionestypepuedentenerlomismoquelasfunciones.PorejemplosideseáramosquenuestrotipoNimplementaseDisplay,demaneraquepudiésemosimprimirlosnodos,podríamoshacerlosiguiente:

usestd::fmt;

traitGrafo{

typeN:fmt::Display;

typeV;

fntiene_vertice(&self,&Self::N,&Self::N)->bool;

fnvertices(&self,&Self::N)->Vec<Self::V>;

}

ImplementandotiposasociadosJustocomocualquierotrotrait,lostraitsqueusantiposasociadoshacenusodelapalabrareservadaimplparaproporcionarimplementaciones.AcontinuaciónunaimplementaciónsimpledeGrafo:

ElLenguajedeProgramacionRust

282TiposAsociados

Page 283: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#traitGrafo{

#typeN;

#typeV;

#fntiene_vertice(&self,&Self::N,&Self::N)->bool;

#fnvertices(&self,&Self::N)->Vec<Self::V>;

#}

structNodo;

structVertice;

structMiGrafo;

implGrafoforMiGrafo{

typeN=Nodo;

typeV=Vertice;

fntiene_vertice(&self,n1:&Nodo,n2:&Nodo)->bool{

true

}

fnvertices(&self,n:&Nodo)->Vec<Vertice>{

Vec::new()

}

}

EstatontaimplementaciónsiempreretornatrueyunVec<Vertice>vacío,perotedaunaideadecomoseimplementaestetipodetraitscontiposasociados.Primeronecesitamostresstructs,unaparaelgrafo,unaparaelnodo,yunaparaelvértice.Dehabertenidomassentidousaruntipodiferente,tambiénhubiesefuncionado,ahorausaremosstructsparalostres.

Losiguienteeslalineaimpl,queesidénticaalaimplementacióndecualquierotrotrait.

Deaquíenadelante,usamos=paradefinirnuestrostiposasociados.Elnombrequeeltraitusavadelladoizquierdodel=,yeltipoenconcretoparaelqueestamosimplementandoestetraitvadelladoderecho.Finalmente,podemosusartiposconcretosennuestrasdeclaracionesdefunción.

ObjetostraitcontiposasociadosHayotrasintaxisdelacualdebemoshablar:objetostrait.Sideseáramoscrearunobjetotraitapartirdeuntipoasociadodeestamanera:

ElLenguajedeProgramacionRust

283TiposAsociados

Page 284: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#traitGrafo{

#typeN;

#typeV;

#fntiene_vertice(&self,&Self::N,&Self::N)->bool;

#fnvertices(&self,&Self::N)->Vec;

#}

#structNodo;

#structVertice;

#structMiGrafo;

#implGrafoforMiGrafo{

#typeN=Node;

#typeV=Vertice;

#fntiene_vertice(&self,n1:&Nodo,n2:&Nodo)->bool{

#true

#}

#fnvertices(&self,n:&Nodo)->Vec{

#Vec::new()

#}

#}

letgrafo=MiGrafo;

letobj=Box::new(grafo)asBox;

Obtendríamosestosdoserrores:

error:thevalueoftheassociatedtype`V`(fromthetrait`main::Grafo`)must

bespecified[E0191]

letobj=Box::new(grafo)asBox;

^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

24:44error:thevalueoftheassociatedtype`N`(fromthetrait

`main::Grafo`)mustbespecified[E0191]

letobj=Box::new(grafo)asBox;

^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Nopodemoscrearobjetostraitdeestamanera,puestoaquenoconocemoslostiposasociados.Ensulugarpodríamosescribir:

ElLenguajedeProgramacionRust

284TiposAsociados

Page 285: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#traitGrafo{

#typeN;

#typeV;

#fnhas_edge(&self,&Self::N,&Self::N)->bool;

#fnedges(&self,&Self::N)->Vec<Self::V>;

#}

#structNodo;

#structVertice;

#structMiGrafo;

#implGrafoforMiGrafo{

#typeN=Nodo;

#typeV=Vertice;

#fntiene_vertice(&self,n1:&Nodo,n2:&Nodo)->bool{

#true

#}

#fnvertices(&self,n:&Nodo)->Vec<Vertice>{

#Vec::new()

#}

#}

letgrafo=MiGrafo;

letobj=Box::new(grafo)asBox<Grafo<N=Nodo,V=Vertice>>;

LasintaxisN=Nodonospermitecrearuntipoconcreto,Nodo,paraelparámetrodetipoN.LomismoconV=Vertice.Denohaberproporcionadoestarestricción,nohubiéramospodidodeterminarcontracualimpldebeserusadoelobjetotrait.

ElLenguajedeProgramacionRust

285TiposAsociados

Page 286: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%TipossinTamaño

Lamayoríadelostiposposeeuntamañoparticular,enbytes,queesconocidoentiempodecompilación.Porejemplouni32tieneuntamañodetreintaydosbits,ocuatrobytes.Sinembargo,hayalgunostiposquesonútilesdeexpresar,peronotienenuntamañodefinido.Dichostipossondenominadostipos‘sintamaño’(‘unsized’)o‘detamañodinámico’(‘dynamicallysized’).Unejemploes[T].DichotiporepresentaciertonumerodeTensecuencia.Peronosabemoscuantosdeelloshay,yenconsecuenciaeltamañoesdesconocido.

Rustentiendealgunosdeestostipos,perotienenalgunasrestricciones.Sontres:

1. Solopodemosmanipularunainstanciadeuntiposintamañoatravésdeunapuntador.Un&[T]funcionaperfecto,peroun[T]no.

2. Lasvariablesyargumentosnopuedentenertiposdetamañodinámico.3. Soloelultimocampoenunstructpuedeteneruntipodedatosdetamañodinámico;

losotroscamposno.Lasvariantesdeenumsnodebentenertiposdetamañodinámicocomodata.

Entonces,porquemolestarse?Bueno,debidoaque[T]puedesoloserusadodetrásdeunapuntador,denotenersoporteaniveldelenguajeparatipossintamaño,seriaimposibleescribirlosiguiente:

implFooforstr{

o

implFoofor[T]{

Ensulugar,tendríasqueescribir:

implFoofor&str{

Significandoqueestaimplementaciónsolofuncionariaparareferencias,ynootrotiposdeapuntadores.Conelimplforstr,todoslosapuntadores,incluyendo(enalgúnpunto,hayalgunosbugsquearreglarprimero)apuntadoresinteligentesdefinidosporelusuario,puedenusaresteimpl.

?Sized

ElLenguajedeProgramacionRust

286TipossinTamaño

Page 287: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Sideseasescribirunafunciónqueacepteuntipodedatosdetamañodinámico,puedesusarlimitedetraitespecial,?Sized:

structFoo<T:?Sized>{

f:T,

}

Este?,leídocomo“TpuedeserSized”,significaqueestelimitedetraitesespecial:nospermitehacermatchconmastipos,nomenos.EsjustocasicomoquecualquierTimplícitamenteesT:Sized,yel?deshaceestecomportamientopordefecto.

ElLenguajedeProgramacionRust

287TipossinTamaño

Page 288: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%OperadoresySobrecarga

Rustpermiteunaformalimitadadesobrecargadeoperadores.Existenciertosoperadoresquepuedensersobrecargados.Parasoportarunoperadorparticularentretipos,hayuntraitenespecificoquepuedesimplementar,elcualsobrecargaeloperador.

Porejemplo,eloperador+puedesersobrecargadoconeltraitAdd:

usestd::ops::Add;

#[derive(Debug)]

structPunto{

x:i32,

y:i32,

}

implAddforPunto{

typeOutput=Punto;

fnadd(self,otro:Punto)->Punto{

Punto{x:self.x+otro.x,y:self.y+otro.y}

}

}

fnmain(){

letp1=Punto{x:1,y:0};

letp2=Punto{x:2,y:3};

letp3=p1+p2;

println!("{:?}",p3);

}

Enmain,podemoshacerusode+ennuestrosdosPuntoss,puestoquehemosimplementadoAdd<Output=Punto>paraPunto.

Existeunnumerodeoperadoresquepuedensersobrecargadosdeestamanera,ytodossustraitsasociadosvivenenelmodulostd::ops.Echaunvistazoaladocumentaciónparaunalistacompleta.

Implementardichostraitssigueunpatron.AnalicemosaAddconmasdetalle:

#modfoo{

pubtraitAdd<RHS=Self>{

typeOutput;

fnadd(self,rhs:RHS)->Self::Output;

}

#}

ElLenguajedeProgramacionRust

288OperadoresySobrecarga

Page 289: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Hayentotaltrestiposinvolucradosaqui:EltipoparaelcualestasimplementadoAdd,RHS(derighthandside),quepordefectoesSelf,yOutput.Paraunaexpresionletz=x+y,xeseltipoSelf,yeselRHS,yzeseltipoSelf::Output.

#structPunto;

#usestd::ops::Add;

implAdd<i32>forPunto{

typeOutput=f64;

fnadd(self,rhs:i32)->f64{

//sumaruni32aunPuntoobteniendounf64

#1.0

}

}

tepermitirahacerlosiguiente:

letp:Point=//...

letx:f64=p+2i32;

UsandolostraitsdeoperadorenestructurasgenericasAhoraquesabemoscomoestándefinidoslostraitsdeoperador,podemosdefinirnuestrotraitTieneAreaynuestraestructuraCuadradodelcapitulodetraitsdeunaformamasgenérica:

ElLenguajedeProgramacionRust

289OperadoresySobrecarga

Page 290: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::ops::Mul;

traitTieneArea<T>{

fnarea(&self)->T;

}

structCuadrado<T>{

x:T,

y:T,

lado:T,

}

impl<T>TieneArea<T>forCuadrado<T>

whereT:Mul<Output=T>+Copy{

fnarea(&self)->T{

self.lado*self.lado

}

}

fnmain(){

lets=Cuadrado{

x:0.0f64,

y:0.0f64,

lado:12.0f64,

};

println!("Areades:{}",s.area());

}

ParaTieneAreayCuadrado,solodeclaramosunparametrodetipoTyreemplazamoself64.Elbloqueimplnecesitamasmodificaciones:

implTieneAreaforCuadrado

whereT:Mul+Copy{...}

Elmétodoarearequierequepodamosmultiplicarloslados,esporelloquedeclaramosqueTdebeimplementarstd::ops::Mul.ComoAdd,mencionadoanteriormente,MultomaunparámetroOutput:debidoaquesabemosquelosnúmerosnocambiandetipocuandosonmultiplicados,tambiénlodefinimoscomoT.Ttambiéndebesoportarcopiado,demaneraqueRustnotratedemoverself.ladoaelvalorderetorno.

ElLenguajedeProgramacionRust

290OperadoresySobrecarga

Page 291: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%CoercionesDeref

LabibliotecaestándarproporcionauntraitespecialDeref.Esusadonormalmenteparasobrecargar*,eloperadordedereferencia:

usestd::ops::Deref;

structEjemploDeref<T>{

valor:T,

}

impl<T>DerefforEjemploDeref<T>{

typeTarget=T;

fnderef(&self)->&T{

&self.valor

}

}

fnmain(){

letx=EjemploDeref{valor:'a'};

assert_eq!('a',*x);

}

Loanterioresútilparaescribirtipospersonalizadosdeapuntadores.Sinembargo,hayunafacilidaddellenguajerelacionadaaDeref:las‘coercionesderef’.Heaquílaregla:SitienesuntipoU,yesteimplementaDeref<Target=T>,losvaloresde&UharáncoercionAutomaticaaun&T.Acontinuaciónunejemplo:

fnfoo(s:&str){

//tomarlacadenaprestadaporunsegundo

}

//StringimplementaDeref<Target=str>

letowned="Hola".to_string();

//entonces,estofunciona:

foo(&owned);

Usandounampersandenfrentedelvalortomamosunareferenciaael.EntoncesownedesunString,&ownedesun&String,ydebidoaimplDeref<Target=str>paraString,&Stringharáderefa&strqueestomadoporfoo().

Esoestodo.DichareglaesunodelosúnicoslugaresenlosqueRusthaceconversionesautomáticaspornosotros,peroalmismotiempoagregamuchaflexibilidad.PorejemploeltipoRc<T>implementaDeref<Target=T>,demaneraqueestofunciona:

ElLenguajedeProgramacionRust

291CoercionesDeref

Page 292: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usestd::rc::Rc;

fnfoo(s:&str){

//tomarlacadenaprestadaporunsegundo

}

//StringimplementaDeref<Target=str>

letowned="Hello".to_string();

letcontado=Rc::new(owned);

//entonces,estofunciona:

foo(&contado);

TodoloquehemoshechoesenvolvernuestroStringenunRc<T>.PeroahorapodemospasarelRc<String>acualquierlugarenelcualtengamosunaString.Lafirmadefoonocambio,perofuncionadeigualformaconcualquieradelosdostipos.Esteejemplotienedosconversiones:deRc<String>aStringyluegodeStringa&str.Rustharáestotantasvecescomoseaposiblehastaquelostiposcoincidan.

Otraimplementaciónmuycomúnproporcionadaporlabibliotecaestándares:

fnfoo(s:&[i32]){

//tomarelpedazoprestadoporunsegundo

}

//Vec<T>implementaDeref<Target=[T]>

letowned=vec![1,2,3];

foo(&owned);

LosvectorespuedenhacerDerefaunslice.

DerefyllamadasametodoDereftambiénentraraenefectocuandosellameaunmétodo.Consideraelsiguienteejemplo:

ElLenguajedeProgramacionRust

292CoercionesDeref

Page 293: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

structFoo;

implFoo{

fnfoo(&self){println!("Foo");}

}

letf=&&Foo;

f.foo();

Aunquefesun&&FooyFoorecibea&self,loanteriorfunciona.Todoestocomoconsecuenciadequetodasestascosassonlomismo:

f.foo();

(&f).foo();

(&&f).foo();

(&&&&&&&&f).foo();

Unvalordetipo&&&&&&&&&&&&&&&&FoopuedeauntenerllamadasamétodosdefinidosenFoodebidoaqueelcompiladorinsertaratantasoperacionesseannecesariasparahacerlofuncionar.Ydebidoaqueinserta`s,sehaceusodeDeref`.

ElLenguajedeProgramacionRust

293CoercionesDeref

Page 294: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Macros

Porahora,hasaprendidomuchosobrelasherramientasqueRustofreceparaabstraeryreutilizarcódigo.Estasunidadesdereutilizaciónposeenunaricaestructurasemántica.Porejemplo,lasfuncionestienenunafirmadetipos,losparámetrosdetipotienenlímitesdetraitsylasfuncionessobrecargadasdebenpertenecerauntraitparticular.

EstaestructurasignificaquelasprincipalesabstraccionesenRustposeenunpoderosomecanismodechequeoentiempodecompilación.Pero,elprecioesunaflexibilidadreducida.Siseidentificavisualmenteunpatróndecódigorepetido,podríaserdifícilotediosoexpresaresepatróncomounafuncióngenérica,untrait,ocualquierotroelementodelasemánticadeRust.

Lasmacrosnospermitenabstraeraunnivelsintáctico.Unainvocacióndemacroeslaabreviaturadeunaformasintáctica"expandida".Dichaexpansiónocurredurantelacompilación,antesdecomprobaciónestática.Comoresultado,lasmacrospuedencapturarmuchospatronesdereutilizacióndecódigoquelasabstraccionesfundamentalesdeRustnopueden.

Elinconvenienteesqueelcódigobasadoenmacrospuedesermásdifícildeentender,porquemenosdelasnormasinternasdeRustaplican.Aligualqueunafunciónordinaria,unamacrobienhechasepuedeutilizarsinentenderdetallesdeimplementación.Sinembargo,puedeserdifícildiseñarunamacroconunbuencomportamiento!Además,loserroresdecompilaciónencódigodemacrossonmásdifícilesdeentender,porquedescribenproblemasenelcódigoexpandido,noaniveldelcódigofuentequeusanlosdesarrolladores.

Estosinconvenienteshacendelasmacrosuna"herramientadeúltimorecurso".Loanteriornoquieredecirquelasmacrossonmalas;formanpartedeRustporqueavecessonnecesariasparacódigoconcisoyabstracto.Simplementemanténencuentaesteequilibrio.

DefiniendounamacroPuedequeyahayasvistolamacrovec!,utilizadaparainicializarunvectorconunnumerocualquieradeelementos.

letx:Vec<u32>=vec![1,2,3];

#assert_eq!(&[1,2,3],&x);

Estonopuedeserunafunciónordinaria,porqueaceptacualquiernúmerodeargumentos.Peropodemosimaginarlocomounaabreviaciónsintácticapara

ElLenguajedeProgramacionRust

294Macros

Page 295: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

letx:Vec<u32>={

letmuttemp_vec=Vec::new();

temp_vec.push(1);

temp_vec.push(2);

temp_vec.push(3);

temp_vec

};

#assert_eq!(&[1,2,3],&x);

Podemosimplementarestaabreviatura,utilizandounamacro:actual

actual.Lapropiadefinicióndevec!enlibcollectionsdifieredela↩

presentadaaquí,porrazonesdeeficienciayreutilización.Algunas

deellassonmencionadasenel[capituloavanzadodemacros][].

macro_rules!vec{

($($x:expr),*)=>{

{

letmuttemp_vec=Vec::new();

$(

temp_vec.push($x);

)*

temp_vec

}

};

}

#fnmain(){

#assert_eq!(vec![1,2,3],[1,2,3]);

#}

¡Whoa!,unmontóndesintaxisnueva.Examinémosloparteporparte.

macro_rules!vec{...}

Loanteriordicequeestamosdefiniendounamacrollamadavec,aligualquefnvecdefiniríaunafunciónllamadavec.Enprosa,informalmenteescribimoselnombredeunamacroconunsignodeexclamación,porejemplo,vec!.Estesignodeexclamaciónespartedelasintaxisdeinvocaciónysirveparadistinguirunamacrodeunafunciónordinaria.

Coincidenciadepatrones

ElLenguajedeProgramacionRust

295Macros

Page 296: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Unamacrosedefineatravésdeunaseriedereglas,lascualessoncasosdecoincidenciadepatrones.Anteriormentevimos

($($x:expr),*)=>{...};

Estoessimilaraunbrazodeunaexpresiónmatch,perolaspruebasparacoincidenciaocurrensobrelosárbolesdesintaxisRustentiempodecompilación.Elpuntoycomaesopcionalenelcasofinal(aquí,elúnicocaso).El"patrón"enelladoizquierdodel=>esconocidocomoun'matcher'.Losmatcherstienensupropiapequeñogramáticadentrodellanguage.

Elmatcher$x:exprcoincidiráconcualquierexpresiónRust,asociandoeseárbolsintácticoala'metavariable'$x.Elidentificadorexpresun'especificadorfragmento';todaslasposibilidadesseenumeranenelcapituloavanzadodemacros.Alrodearelmatchercon$(...),*,coincidiráconceroomásexpresionesseparadasporcomas.

Ademasdelasintaxisespecialdematchers,lostokensRustqueaparecenenunmatcherdebencoincidirdemaneraexacta.Porejemplo:

macro_rules!foo{

(x=>$e:expr)=>(println!("modoX:{}",$e));

(y=>$e:expr)=>(println!("modoY:{}",$e));

}

fnmain(){

foo!(y=>3);

}

imprimirá

modoY:3

Con

foo!(z=>3);

obtenemoselerrordelcompilador

error:norulesexpectedthetoken`z`

Expansión

ElLenguajedeProgramacionRust

296Macros

Page 297: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

ElladoderechodeunareglamacroessintaxisRustordinaria,ensumayorparte.Peropodemosinsertarpartesdesintaxiscapturadasporelmatcher.Delejemplooriginal:

$(

temp_vec.push($x);

)*

Cadaexpresióncoincidente$xproduciráunasolaexpresiónpushenlaexpansióndelamacro.Larepeticiónsedesarrollaen"lockstep"conlarepeticiónenelmatcher(mássobreestoenunmomento).

Debidoaque$xyafuemarcadocomounacoincidenciaconunaexpresión,norepetimos:exprenelladoderecho.Además,noincluimosunacomaseparandocomopartedeloperadorderepetición.Encambio,tenemosunpuntoycomaqueterminadentrodelbloquerepetido.

Otrodetalle:lamacrovectienedosparesdellavesenelladoderecho.Amenudosecombinandeestemodo:

macro_rules!foo{

()=>{{

...

}}

}

Lasllavesexterioressonpartedelasintaxisdemacro_rules!.Dehecho,sepuedeutilizar()o[]ensulugar.Simplementedelimitanelladoderechocomountodo.

Lasllavesinterioressonpartedelasintaxisexpandida.Recuerdaquelamacrovec!seutilizaenuncontextodeexpresión.Paraescribirunaexpresiónconvariassentencias,entreellasenlacesavariable,utilizamosunbloque.Silamacroseexpandeaunasolaexpresión,nonecesitasdichacapaextradellaves.

Hayquetenertambiénencuentaquenuncadeclaramosquelamacroproduceunaexpresión.Dehecho,estonosedeterminahastaqueusamoslamacrocomounaexpresión.Concuidado,sepuedeescribirunamacrocuyaexpansiónfuncioneenvarioscontextos.Porejemplo,laabreviaturadeuntipodedatospodríaserválidacomounaexpresiónounpatrón.

RepeticiónEloperadorderepeticiónsiguedosreglasprincipales:

ElLenguajedeProgramacionRust

297Macros

Page 298: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

1. $(...)*caminaatravésdeuna"capa"derepeticiones,paratodoslos$nombresquecontiene,almismopaso,y

2. cada$nombredebeestarbajoalmenostantos$(...)*comolosquefuecomparado.Siestabajomás,seraduplicado,segúnelcaso.

Estamacrobarrocailustraladuplicacióndelasvariablesdelosnivelesderepeticiónexteriores.

macro_rules!o_O{

(

$(

$x:expr;[$($y:expr),*]

);*

)=>{

&[$($($x+$y),*),*]

}

}

fnmain(){

leta:&[i32]

=o_O!(10;[1,2,3];

20;[4,5,6]);

assert_eq!(a,[11,12,13,24,25,26]);

}

Esaeslamayorpartedelasintaxisdelosmatcher.Todoslosejemplosutilizan$(...)*,quecoincidecon"ceroomás"elementossintácticos.Alternativamente,puedesescribir$(...)+quecoincidecon"unoomás".Ambasformasincluyen,opcionalmente,unseparador,quepuedesercualquiertokenexcepto+o*.

Estesistemasebasaen"Macro-by-Example"(PDF).

HigieneAlgunoslenguajesimplementanmacrosconsustitucióndetextosimple,loquetraecomoconsecuenciadiversosproblemas.Porejemplo,esteprogramaCimprime13enlugardelaesperada25.

#defineCINCO_VECES(x)5*x

intmain(){

printf("%d\n",CINCO_VECES(2+3));

return0;

}

ElLenguajedeProgramacionRust

298Macros

Page 299: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Despuésdelaexpansióntenemos5*2+3,endondelamultiplicacióntienemayorprecedenciaquelasuma.SihasutilizadomuchosmacrosenC,probablementeconoceslosidiomasestándarparaevitaresteproblema,asícomocincooseisotros.EnRust,nonospreocupamosporello.

macro_rules!cinco_veces{

($x:expr)=>(5*$x);

}

fnmain(){

assert_eq!(25,cinco_veces!(2+3));

}

Lametavariable$xseanalizacomounnododeexpresiónindividual,ymantienesulugarenelárboldesintaxis,inclusodespuésdelasustitución.

Otroproblemacomúnenlossistemasdemacroesla"capturadevariable".AquíhayunamacroC,utilizandounaextensióndeGNUCparaemularbloquesdeexpresióndeRust.

#defineLOG(msj)({\

intestado=obtener_estado_log();\

if(estado>0){\

printf("log(%d):%s\n",estado,msj);\

}\

})

Heaquíuncasodeusoquevaterriblementemal:

constchar*estado="estríasreticuladas";

LOG(estado)

Loanteriorseexpandea

constchar*estado="estríasreticuladas";

intestado=obtener_estado_log();

if(estado>0){

printf("log(%d):%s\n",estado,estado);

}

Lasegundavariablellamadaestadosobreescribealaprimera.Estoesunproblemaporquelaexpresióndeimpresión(printf)debehacerreferenciaaambas.

LamacroRustequivalentetieneelcomportamientodeseado.

ElLenguajedeProgramacionRust

299Macros

Page 300: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#fnobtener_estado_log()->i32{3}

macro_rules!log{

($msj:expr)=>{{

letestado:i32=obtener_estado_log();

ifestado>0{

println!("log({}):{}",estado,$msj);

}

}};

}

fnmain(){

letestado:&str="estríasreticuladas";

log!(estado);

}

EstaversiónfuncionaporqueRusttieneunsistemademacroshigiénico.Cadaexpansióndemacroocurreenun"contextodesintaxis"distinto,ycadavariableestáasociadaconelcontextodesintaxisdondefueintroducida.Escomosilavariableestadodentromainestápintadodeun"color"diferentedelavariableestadodentrodelamacro,yporlotantonoentranenconflicto.

ElsistemademacrosdeRusttambiénrestringelacapacidaddelasmacrosparaintroducirnuevosenlacesenelsitiodeinvocación.Códigocomoelsiguientenofuncionará:

macro_rules!foo{

()=>(letx=3);

}

fnmain(){

foo!();

println!("{}",x);

}

Enlugardeesonecesitaspasarelnombredelavariableenlainvocación,demaneraqueseaestiquetadoconelcontextodesintaxiscorrecto.

macro_rules!foo{

($v:ident)=>(let$v=3);

}

fnmain(){

foo!(x);

println!("{}",x);

}

ElLenguajedeProgramacionRust

300Macros

Page 301: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Loanterioresválidoparaenlacesletyetiquetasdebucle,peronoparaitems.Asíqueelsiguientecódigocompila:

macro_rules!foo{

()=>(fnx(){});

}

fnmain(){

foo!();

x();

}

MacrosrecursivasLaexpansióndeunamacropuedeincluirmásinvocacionesamacro,incluyendoinvocacionesdelamismamacroqueestasiendoexpandida.Estasmacrosrecursivassonútilesparaelprocesamientodeentradaconestructuradeárbol,comoseilustraenesta(simplista)taquigrafíaHTML:

ElLenguajedeProgramacionRust

301Macros

Page 302: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

##![allow(unused_must_use)]

macro_rules!write_html{

($w:expr,)=>(());

($w:expr,$e:tt)=>(write!($w,"{}",$e));

($w:expr,$tag:ident[$($inner:tt)*]$($rest:tt)*)=>{{

write!($w,"<{}>",stringify!($tag));

write_html!($w,$($inner)*);

write!($w,"</{}>",stringify!($tag));

write_html!($w,$($rest)*);

}};

}

fnmain(){

#//FIXME(#21826)

usestd::fmt::Write;

letmutout=String::new();

write_html!(&mutout,

html[

head[title["Macrosguide"]]

body[h1["Macrosarethebest!"]]

]);

assert_eq!(out,

"<html><head><title>Macrosguide</title></head>\

<body><h1>Macrosarethebest!</h1></body></html>");

}

DepurandocódigodemacroParaverlosresultadosdelasmacrosenexpansión,ejecutarustc--prettyexpanded.Lasalidarepresentatodouncrate,porloquetambiénpuedealimentardenuevoarustc,queasuvezproducirámejoresmensajesdeerrorquelacompilacióninicial.Esimportantedestacarquelasalidade--prettyexpandedpuedetenerunsignificadodiferentesivariasvariablesdelmismonombre(perodiferentescontextossintácticos)estánenjuegoenelmismoámbito.Enestecaso--prettyexpanded,hygienetediráacercadeloscontextosdesintaxis.

rustcofrecedosextensionesdesintaxisqueayudanconladepuracióndemacros.Porahora,soninestablesyrequierenpuertasdecaracterísticas(featuregates).

log_syntax!(...)imprimirásusargumentosenlasalidaestándar,entiempodecompilación,yse"expandirá"anada.

ElLenguajedeProgramacionRust

302Macros

Page 303: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

trace_macros!(true)habilitaraunmensajecompiladorcadavezqueunamacroesexpandida.Usetrace_macros!(false)adelanteenlaexpansiónparaapagarlo.

MasinformaciónElcapituloavanzadodemacrosentraenmasdetallesacercadelasintaxisdemacros.Tambiéndescribecomocompartirmacrosentrediferentescratesymódulos.

ElLenguajedeProgramacionRust

303Macros

Page 304: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%ApuntadoresPlanos

ElLenguajedeProgramacionRust

304ApuntadoresPlanos

Page 305: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Unsafe

LaprincipalatraccióndeRustsonsuspoderosasgarantíasestáticasacercadecomportamiento.Peroloschequeosdeseguridadsonconservadorespornaturaleza:existenprogramasquesonenefectoseguros,peroelcompiladornoescapazdedeverificarqueestoseacierto.Paraescribiresetipodeprogramas,debemosdecirlealcompiladorquerelajeunpocosusrestricciones.Paraello,Rustposeeunapalabrareservada,unsafe.Elcódigoquehaceusodeunsafeposeemenosrestriccionesqueelcódigonormal.

Repasemoslasintaxis,yluegohablaremosdelasemántica.unsafeesusadoencuatrocontextos.Elprimeroesparamarcarunafuncióncomoinsegura:

unsafefnpeligro_will_robinson(){

//cosaspeligrosas

}

TodaslasfuncionesllamadasdesdeFFIdebensermarcadascomounsafe,porejemplo.Elsegundousodeunsafeesunbloqueunsafe:

unsafe{

//osaspeligrosas

}

Elterceroesparatraitsunsafe:

unsafetraitPeligroso{}

Ylacuartaesparalaimplementacióndeunodedichostraits:

#unsafetraitPeligroso{}

unsafeimplPeligrosofori32{}

Esimportantepodertenerlacapacidaddedelinearcódigoquepodríaposiblementecontenerbugsqueoriginenproblemasgraves.SiunprogramaRustterminademaneraabrupta(unsegfault),puedestenerporseguroqueesenalgúnlugardelasseccionesmarcadascomounsafe.

Quesignifica‘seguro’?

ElLenguajedeProgramacionRust

305`unsafe`

Page 306: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Seguro,enelcontextodeRust,significa‘nohacernadainseguro’.Esimportantesaberquehayciertoscomportamientosquesonprobablementeindeseablesentucódigo,perosonexpresamentenoinseguros:

Deadlocks.Perdidadememoriauotrosrecursos.Salidasinllamadaalosdestructores.Desbordamientodeenteros.

Rustnopuedeprevenirtodoslostiposdeproblemasdesoftware.Lascosasdelalistaanteriornosonbuenas,perotampococalificancomounsafeespecíficamente.

Enadición,lossiguientessontodoscomportamientoindefinidoenRust,ydebenserevitadas,inclusocuandoseescribecódigounsafe:

Condicionesdecarrera.Deereferenciarunapuntadornulo/colgante.Lecturadememoriaundef(memorianoinicializada)Violacióndelasreglasdealiasingdeapuntadoresatravésdeapuntadoresplanos.&mutTy&TsiguenelmodelonoaliasdeLLVM,exceptocuandoel&TcontieneunUnsafeCell<U>.Elcódigounsafenodebeviolaresasgarantíasdealiasing.Mutarunvalor/referenciainmutablesinunUnsafeCell<U>.Invocarcomportamientoindefinidoatravésdeintrínsecosdelcompilador:

Indexarporfueradeloslimitesdeunobjetoconstd::ptr::offset(intrínsecooffset),conlaexcepcióndeunsolobytedespuésdelfinallocualespermitido.Usarstd::ptr::copy_nonoverlapping_memory(intrínsecosmemcpy32/memcpy64)enbuffersquesesolapen.

Valoresinválidosentiposprimitivos,inclusoencampos/variableslocalesprivadas:Referenciasnull,referenciascolgantesoboxes.Unvalordistintoquefalse(0)otrue(1)enunbool.Undiscriminanteenunenumquenoesteincluidoensudefinicióndetipo.Unvalorenuncharelcualesunsustitutooporencimadechar::MAX.Unasecuenciadebytesno-UTFenunstr.

UnwindingenRustdesdecódigoforaneoounwindingdesdeRustacódigoforaneo.

SuperpoderesUnsafeEnambosfuncionesybloquesunsafe,Rusttepermitiráhacertrescosasquenormalmentenopodríashacer.Solotres.Yson:

1. Accederoactualizarunavariablemutableestética.

ElLenguajedeProgramacionRust

306`unsafe`

Page 307: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

2. Dereferenciarunapuntadorplano.3. Llamarafuncionesunsafe.Estaeslahabilidadmasimportante.

Esoestodo.Esimportantedestacarqueunsafe,porejemplo,no‘apagaelcomprobadordeprestamos’.Agregardemaneraaleatoriaunsafeaalgúncódigonocambiasusemántica,nocomenzaraaaceptaralgo.Perotepermitiráescribircosasquesirompenalgunasdelasreglas.

Tambiénencontraraslapalabrareservadaunsafecuandoescribasbindingsainterfacesforáneas(no-Rust).LomasrecomendableesescribirunasegurainterfaznativaenRustalrededordelosmétodosproporcionadosporlalibrería.

Echemosunvistazoalastreshabilidadeslistadas,enorden.

AccederoactualizarunastaticmutRustposeeunafacilidaddenominada‘staticmut’quetepermitehacerestadoglobalmutable.Hacerlopuedecausarunacondicióndecarrera,yenconsecuenciaesinherentementeinseguro.Paramayordetalle,dirígetealasecciónstaticdellibro.

DereferenciarunapuntadorplanoLosapuntadoresplanostepermitenllevaracaboaritméticadepunterosarbitraria,ypuedencausarunnumerodeproblemasdeseguridad.Enalgunossentidos,lahabilidaddedereferenciarunapuntadorarbitrarioesunadelascosasmaspeligrosasquepuedeshacer,masinformaciónensusecciónenellibro.

LlamarfuncionesunsafeEstaultimahabilidadfuncionaconambosaspectosdeunsafe:puedessolollamarafuncionesmarcadascomounsafedesdedentrodeunbloqueunsafe.

Estahabilidadespoderosayvariada.Rustexponealgunosintrínsecosdelcompiladorcomofuncionesunsafe,yalgunasfuncionesunsafehacenbypassdealgunoschequeosdeseguridad,intercambiandoseguridadporvelocidad.

Lorepetirédenuevo:aunycuandopuedeshacercosasarbitrariasenbloquesunsafeyfuncionesnosignificaquedebashacerlo.Elcompiladoractuaracomosituereselresponsableestuviesesdemantenerarribatodaslasinvariantes,asíquedebessercuidadoso!

ElLenguajedeProgramacionRust

307`unsafe`

Page 308: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%RustNocturno

Rustproporcionatrescanalesdedistribución:nocturno(nightly),betayestable(stable).LasfacilidadesinestablesestánsolodisponiblesenRustnocturno.Paramayordetalleacercadeesteproceso,véase‘Estabilidadcomounentregable’.

ParainstalarRustnocturno,puedesusarrustup.sh:

$curl-shttps://static.rust-lang.org/rustup.sh|sh-s----channel=nightly

Sitienesalgunadudaacercadela[inseguridadpotencial]delusodecurl|sh,porfavor,continualeyendoyencontrarasnuestrodisclaimer.Siéntetetambiénenlibertaddeusarunaversiondedospasosdelainstalaciónexaminandonuestroscript:

$curl-f-Lhttps://static.rust-lang.org/rustup.sh-O

$shrustup.sh--channel=nightly

SiestasenWindows,porfavordescargabienseaelinstaladorde32bitsoelinstaladorde64bitsyejecutalo.

DesinstalandoSihasdecididoqueyanoquieresmasaRust,estaremosunpocotriste,peroestabien.Notodosloslenguajesdeprogramaciónsonparatodoelmundo.Simplementeejecutaelscriptdedesinstalación:

$sudo/usr/local/lib/rustlib/uninstall.sh

SiusasteelinstaladordeWindows,simplementeejecutael.msidenuevoyestetedarálaopcióndedesinstalación.

Algunaspersonas,ydealgunaformaconderecho,sesientenperturbadoscuandolesdecimosquehagancurl|sh.Básicamente,cuandohacesesto,estasconfiandoquelabuenagentequemantieneRustnovanahackeartucomputadorayhacercosasmalas.Esoes=bueninstinto!Sieresunadeesaspersonas,porfavorechaunvistazoaladocumentaciónacercadelainstalacióndeRustdesdefuentes.Olasdescargasdelosejecutablesoficiales.

Ah,debemosmencionarlasplataformasoficialmentesoportadas:

Windows(7,8,Server2008R2)Linux(2.6.18omayor,variasdistribuciones),x86andx86-64

ElLenguajedeProgramacionRust

308RustNocturno

Page 309: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

OSX10.7(Lion)omayor,x86andx86-64

Nosotros,elequipodeRustprobamosRustdemaneraextensivaenesasplataformas,yotraspocasmas,comoAndroid.Peroestassonlasmaspropensasenfuncionarcorrectamente,debidoaquesonlasqueposeenmaspruebas.

Finalmente,uncomentarioacercadeWindows.RustconsideraaWindowscomounaplataformadeprimeraclaseenloqueserefierealrelease,perosisomoshonestos,laexperienciaenWindowsnoestatanintegradacomolasexperienciasenLinuxyOSX.Estamostrabajandoenello!Sialgonofunciona,esunbug.Porfavorhaznossabersiesopasa.CadacommmitesprobadoenWindowsjustocomocualquierotraplataforma.

SihasinstaladoRust,puedesabrirunaterminal,yescribir:

$rustc--version

Deberíasverelnumerodeversion,elhashdecommit,fechadelcommityfechadecompilación:

rustc1.0.0-nightly(f11f3e7ba2015-01-04)(built2015-01-06)

Siloves,Rusthasidoinstaladosatisfactoriamente!Felicidades!

Esteinstaladortambiéninstalaunacopialocaldeladocumentación,demaneraquepuedasleerlaoffline.EnsistemasUNIX,lalocaciónes/usr/local/share/doc/rust.Enwindows,seubicaeneldirectorioshare/doc,endondeseaquehayasinstaladoRust.

Sino,hayunavariedaddelugaresenlosquepuedessolicitarayuda.Elmasfácileselcanal#rustenirc.mozilla.org,elcualpuedesaccederviaMibbit.Cliqueaeseenlace,yestaráschateandoconRutaceos(untontoapodoconelquenosreferimosanosotros),ypodremosayudarte.Otrosmuybuenosrecursosincluyenelforodeusuarios,yStackOverflow.

ElLenguajedeProgramacionRust

309RustNocturno

Page 310: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%PluginsdelCompilador

Introducciónrustcpuedecargarpluginsdecompilador,quesonbibliotecasdeusuarioqueextiendenelcomportamientodelcompiladorconnuevasextensionesdesintaxis,lints,etc.

Unpluginpuedeserunabibliotecadinámicaconunafunciónregistradoradesignadaseencargaregistrarlaextensionconrustc.Otroscratespuedencargarestasextensionesatravésdelusodelatributo#![plugin(...)].Dirígetealadocumentaciónderustc_pluginparamayordetalleacercadelamecánicadeladefiniciónycargadeunplugin.

Deestarpresentes,losargumentospasadoscomo#![plugin(foo(...args...))]nosoninterpretadosporrustc.SonproporcionadosalpluginatravésdelmétodoargsdeRegistry.

Enlagranmayoríadeloscasos,unpluginsolodeberíaserusadoatravésde#![plugin]ynopormediodeunitemexterncrate.Enlazarunplugintraeríaalibsyntaxylibrustccomodependenciasdetucrate.Estoesgeneralmenteindeseableamenosqueestésconstruyendounplugin.Ellintplugin_as_librarychequeaestoslineamientos.

Lapracticausualescolocaralospluginsdelcompiladorensupropiocrate,separadosdecualquiermacromacro_rules!ocódigoRustordinarioquevayanaserusadosporlosconsumidoresdelabiblioteca.

ExtensionesdesintaxisLospluginspuedenextenderlasintaxisdeRustdevariasmaneras.Unaformadeextensiondesintaxissonlasmacrosprocedurales.Estassoninvocadasdelamismaformaquelasmacrosordinarias,perolaexpansiónesllevadaacaboporcódigoRustarbitrarioquemanipulaarbolesdesintaxisentiempodecompilación.

Escribamosunpluginroman_numerals.rsqueimplementaliteralesdeenterosconnúmerosromanos.

#![crate_type="dylib"]

#![feature(plugin_registrar,rustc_private)]

externcratesyntax;

externcraterustc;

externcraterustc_plugin;

ElLenguajedeProgramacionRust

310PluginsdelCompilador

Page 311: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

usesyntax::codemap::Span;

usesyntax::parse::token;

usesyntax::ast::TokenTree;

usesyntax::ext::base::{ExtCtxt,MacResult,DummyResult,MacEager};

usesyntax::ext::build::AstBuilder;//traitparaexpr_usize

userustc_plugin::Registry;

fnexpand_rn(cx:&mutExtCtxt,sp:Span,args:&[TokenTree])

->Box{

staticNUMERALS:&'static[(&'staticstr,usize)]=&[

("M",1000),("CM",900),("D",500),("CD",400),

("C",100),("XC",90),("L",50),("XL",40),

("X",10),("IX",9),("V",5),("IV",4),

("I",1)];

ifargs.len()!=1{

cx.span_err(

sp,

&format!("argumentshouldbeasingleidentifier,butgot{}arguments",args.len()));

returnDummyResult::any(sp);

}

lettext=matchargs[0]{

TokenTree::Token(_,token::Ident(s,_))=>s.to_string(),

_=>{

cx.span_err(sp,"argumentshouldbeasingleidentifier");

returnDummyResult::any(sp);

}

};

letmuttext=&*text;

letmuttotal=0;

while!text.is_empty(){

matchNUMERALS.iter().find(|&&(rn,_)|text.starts_with(rn)){

Some(&(rn,val))=>{

total+=val;

text=&text[rn.len()..];

}

None=>{

cx.span_err(sp,"invalidRomannumeral");

returnDummyResult::any(sp);

}

}

}

MacEager::expr(cx.expr_usize(sp,total))

}

#[plugin_registrar]

pubfnplugin_registrar(reg:&mutRegistry){

reg.register_macro("rn",expand_rn);

}

ElLenguajedeProgramacionRust

311PluginsdelCompilador

Page 312: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Entoncespodemoshacerusodern!()comocualquierotramacro:

#![feature(plugin)]

#![plugin(roman_numerals)]

fnmain(){

assert_eq!(rn!(MMXV),2015);

}

Lasventajasdeestoporencimadeunasimplefn(&str)->u32son:

Laconversión(arbitrariamentecompleja)esefectuadaentiempodecompilación.Lavalidacióndeentradaestambiénllevadaacaboentiempodecompilación.Puedeserextendidaparasuusoenpatrones,locaulefectivamenteproporcionaunaformadedefinirunasintaxisliteralnuevaparacualquiertipodedato.

Enadicionalasmacrosprocedurales,puedesdefinirattributosderiveyotrostiposdeexpansiones.DirigeteaRegistry::register_syntax_extensionyaelenumSyntaxExtension.Paraunejemplomasinvolucradoconmacros,vearegex_macros.

TipsytrucosAlgunosdelostipsdedepuracióndemacrossonaplicables.

Puedesusarsyntax::parseparatransformararbolesdetokensenelementosdesintaxisdemasaltonivel,comoexpresiones:

fnexpandir_foo(cx:&mutExtCtxt,sp:Span,args:&[TokenTree])

->Box{

letmutparser=cx.new_parser_from_tts(args);

letexpr:P=parser.parse_expr();

Miraraelcódigodelparserlibsyntaxtedaraunaideadecomofuncionalainfraestructuradeparseo.

ManténlosSpansdetodoloqueparsees,paraunmejorreportedeerrores.PuedesenvolverSpannedalrededordetusestructurasdedatos,

ElLenguajedeProgramacionRust

312PluginsdelCompilador

Page 313: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

LlamaraExtCtxt::span_fatalabortarademanerainmediatalacompilación.EsmejorllamaraExtCtxt::span_errretornandounDummyResult,demaneraqueelcompiladorpuedacontinuarencontrandomaserrores.

Paraimprimirfragmentosdesintaxisparadepuración,pudesusarspan_noteenconjunciónconsyntax::print::pprust::*_to_string.

ElejemploanteriorprodujounliteraldeenterousandoAstBuilder::expr_usize.ComoalternativaaeltraitAstBuilder,libsyntaxproporcionaunconjuntodemacrosquasiquote.Estosestánindocumentadosyunpocorústicosenlosbordes.Sinembargo,laimplementaciónpuedeserunbuenpuntodepartidaparaunquasiquotemejoradocomounabibliotecapluginordinaria.

PluginslintLospluginspuedenextenderlainfraestructuradelintsdeRustconchequeosadicionalesparaestilodecódigo,seguridad,etc.Escribamosahoraunpluginlint_plugin_test.rsquenosadvierteacercadecualquieritemllamadolintme.

ElLenguajedeProgramacionRust

313PluginsdelCompilador

Page 314: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#![feature(plugin_registrar)]

#![feature(box_syntax,rustc_private)]

externcratesyntax;

//Cargandorustccomounpluginparaobtenerlasmacros

#[macro_use]

externcraterustc;

externcraterustc_plugin;

userustc::lint::{EarlyContext,LintContext,LintPass,EarlyLintPass,

EarlyLintPassObject,LintArray};

userustc_plugin::Registry;

usesyntax::ast;

declare_lint!(TEST_LINT,Warn,"Warnaboutitemsnamed'lintme'");

structPass;

implLintPassforPass{

fnget_lints(&self)->LintArray{

lint_array!(TEST_LINT)

}

}

implEarlyLintPassforPass{

fncheck_item(&mutself,cx:&EarlyContext,it:&ast::Item){

ifit.ident.name.as_str()=="lintme"{

cx.span_lint(TEST_LINT,it.span,"itemisnamed'lintme'");

}

}

}

#[plugin_registrar]

pubfnplugin_registrar(reg:&mutRegistry){

reg.register_early_lint_pass(boxPassasEarlyLintPassObject);

}

Entoncescódigocomo

#![plugin(lint_plugin_test)]

fnlintme(){}

produciráunaadvertenciadelcompilador:

foo.rs:4:1:4:16warning:itemisnamed'lintme',#[warn(test_lint)]onbydefault

foo.rs:4fnlintme(){}

^~~~~~~~~~~~~~~

ElLenguajedeProgramacionRust

314PluginsdelCompilador

Page 315: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Loscomponentesdeunpluginlintson:

unaomasinvocacionesdeclare_lint!,lascualesdefinesstructsLint.

unstructmanteniendoelestadonecesarioparaelpasslint(aquí,ninguno);

unaimplementaciónLintPassdefiniendocomochequearcadaelementodesintaxis.UnúnicoLintPasspuedellamaraspan_lintparadiferentesLints,perodeberegistrarlosatodosatravésdelmétodoget_lints.

Lospasseslintsonrecorridosdesintaxis,perocorrenenunaetapadelacompilaciónenlaquelainformacióndetiposestadisponible.LoslintsintegradosdeRustusanmayormentelainfraestructuradelospluginslint,yproveenejemplosdecomoaccederalainformacióndetipos.

Loslintsdefinidosporpluginssoncontroladosporlosflagsyatributosusualesdelcompilador,e.j#[allow(test_lint)]o-Atest-lint.estosidentificadoressonderivadosdelprimerargumentosadeclare_lint!,conlasconversionesdecapitalizaciónypuntuaciónapropiadas.

Puedesejecutarrustc-Whelpfoo.rsparaverunalistadeloslintsquerustcconoce,incluyendoaquellosproporcionadosporpluginscargadosporfoo.rs.

ElLenguajedeProgramacionRust

315PluginsdelCompilador

Page 316: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Ensambladorenlinea

Paramanipulacionesdemuybajonivelyporrazonesdedesempeño,unopodríadesearcontrolarlaCPUdemaneradirecta.ParaestoRustsoportaelusodeensambladorenlineaatravésdelamacroasm!.LasintaxisesparecidaaladeGCC&Clang:

asm!(plantillaensamblador

:operandosdesalida

:operandosdeentrada

:clobbers

:opciones

);

Cualquierusodeasmestaprotegidoporpuertasdefeature(requiere#![feature(asm)]enelcrate)yporsupuestorequieredeunbloqueunsafe.

Nota:losejemplosproporcionadosaquíestánescritosenensambladorx86/x86-64,perotodaslasplataformasestánsoportadas.

PlantillaensambladorLaplantillaensambladoreselúnicoparámetromandatorioydebeserunliteraldecadenadecaracteres(e.j."")

#![feature(asm)]

#[cfg(any(target_arch="x86",target_arch="x86_64"))]

fnfoo(){

unsafe{

asm!("NOP");

}

}

//otrasplataformas

#[cfg(not(any(target_arch="x86",target_arch="x86_64")))]

fnfoo(){/*...*/}

fnmain(){

//...

foo();

//...

}

(Losfeature(asm)y#[cfg]ssonomitidosdeahoraenadelante.)

ElLenguajedeProgramacionRust

316EnsambladorenLinea

Page 317: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Losoperandosdesalida,operandosdeentrada,clobbersyopcionessontodosopcionalesperodebesagregarelnumerocorrectode:encasodequedeseessaltarlos:

##![feature(asm)]

##[cfg(any(target_arch="x86",target_arch="x86_64"))]

#fnmain(){unsafe{

asm!("xor%eax,%eax"

:

:

:"{eax}"

);

#}}

Losespaciosenblanconosonsignificativos:

##![feature(asm)]

##[cfg(any(target_arch="x86",target_arch="x86_64"))]

#fnmain(){unsafe{

asm!("xor%eax,%eax":::"{eax}");

#}}

OperandosLosoperandosdeentradaysalidasiguenelmismoformato:restriccion1"(expr1),"restriccion2"(expr2),...".Lasexpresionesdeoperandosdesalidadebenservaloreslvaluemutables,ovaloresaunnoasignados:

##![feature(asm)]

##[cfg(any(target_arch="x86",target_arch="x86_64"))]

fnadd(a:i32,b:i32)->i32{

letc:i32;

unsafe{

asm!("add$2,$0"

:"=r"(c)

:"0"(a),"r"(b)

);

}

c

}

##[cfg(not(any(target_arch="x86",target_arch="x86_64")))]

#fnadd(a:i32,b:i32)->i32{a+b}

fnmain(){

assert_eq!(add(3,14159),14162)

}

ElLenguajedeProgramacionRust

317EnsambladorenLinea

Page 318: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Sinembargo,Sidesearasusaroperandosrealesenestaposición,seriaobligatoriocolocarllaves{}alrededordelregistroquedeseas,ytambiénestaríasobligadoacolocareltamañoespecificodeloperando.Loanterioresmuyutilparaprogramacióndemuybajonivel,paralaqueesimportantecualregistroeselqueseausa.

##![feature(asm)]

##[cfg(any(target_arch="x86",target_arch="x86_64"))]

#unsafefnread_byte_in(puerto:u16)->u8{

letresultado:u8;

asm!("in%dx,%al":"={al}"(resultado):"{dx}"(puerto));

resultado

#}

ClobbersAlgunasinstruccionesmodificanregistrosloscualesdeotraformahubieranmantenidovaloresdiferentesesporelloqueusamoslaslistadeclobbersparaindicaralcompiladoraquenoasumaqueningúnvalorcargadoendichosregistrossemantendrávalido.

##![feature(asm)]

##[cfg(any(target_arch="x86",target_arch="x86_64"))]

#fnmain(){unsafe{

//Colocandoelvalor0x200eneax

asm!("mov$$0x200,%eax":/*sinsalidas*/:/*sinentradas*/:"{eax}");

#}}

Losregistrosdeentradaysalidanonecesitanserlistadospuestoaqueesainformaciónyaestacomunicadaporlasdeterminadasrestricciones.Delocontrario,cualquierotroregistrousadoyaseademaneraexplicitaoimplícitadebeserlistado.

Sielensambladorcambiaelregistrodecódigodecondiciónccdebeserespecificadocomounodelosclobbers.Similarmente,sielensambladormodificamemoria,memorydebesertambiénespecificado.

OpcionesLaultimasección,opcionesesespecíficadeRust.Elformatoesunalistadecadenasdecaracteresseparadasporcomma(e.j::"foo","bar","baz").Esusadoparaespecificarinformaciónextraacercadelensamblador:

Lasopcionesvalidasactualmenteson:

ElLenguajedeProgramacionRust

318EnsambladorenLinea

Page 319: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

1. volatile-especificarestoesanalogoa__asm____volatile__(...)engcc/clang.2. alignstack-ciertasinstruccionesesperanquelapilaestealineadadeciertamanera

(e.j.SSE),especificarestoleindicaalcompiladorqueinsertesucódigodealineamientodepilausual.

3. intel-usodelasintaxisdeintelenlugardelaAT&T.

##![feature(asm)]

##[cfg(any(target_arch="x86",target_arch="x86_64"))]

#fnmain(){

letresultado:i32;

unsafe{

asm!("moveax,2":"={eax}"(resultado):::"intel")

}

println!("eaxesactualmente{}",resultado);

#}

MasInformaciónLaimplementaciónactualdelamacroasm!esunbindingdirectoalasexpresionesensambladorenlineadeLLVM,asíqueaseguratedeecharleunvistazoasudocumentaciónparamayorinformaciónacercadeclobbers,restricciones,etc.

ElLenguajedeProgramacionRust

319EnsambladorenLinea

Page 320: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Nostdlib

ElLenguajedeProgramacionRust

320Nostdlib

Page 321: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%Intrínsecos

Nota:losintrínsecosporsiempretendránunainterfazinestable,serecomiendausarlasinterfacesestablesdelibcoreenlugardeintrínsecosdirectamente.

EstassonimportadascomosifuesenfuncionesFFI,conelABIespecialrust-intrinsic.Porejemplo,siunoestuvieseenuncontextolibre,perodeseasepoderhacertransmuteentretipos,yllevaracaboaritméticadeapuntadoreseficiente,unoimportaríadichasfuncionesviaunadeclaracióncomo:

#![feature(intrinsics)]

#fnmain(){}

extern"rust-intrinsic"{

fntransmute<T,U>(x:T)->U;

fnoffset<T>(dst:*constT,offset:isize)->*constT;

}

AligualquecualquierotrafunciónFFI,estassonsiempreunsafedellamar.

ElLenguajedeProgramacionRust

321Intrínsecos

Page 322: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%ItemsdeLenguaje

ElLenguajedeProgramacionRust

322ItemsdeLenguaje

Page 323: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%EnlaceAvanzado

LoscasoscomunesdeenlaceconRusthansidocubiertosanteriormenteenestelibro,perosoportarelrangodeposibilidadesdisponiblesenlenguajesesimportanteparaRustparalograrunabuenainteracciónconbibliotecasnativas.

ArgumentosdeenlaceHayotraformadedecirlearustccomopersonalizarelenlazado,yesviaelatributolink_args.Esteatributoesaplicadoalosbloquesexternyespecificaflagsplanosquenecesitanserpasadosaelenlazadorcuandoseproduceunartefacto.Unejemplopodríaser:

#![feature(link_args)]

#[link_args="-foo-bar-baz"]

extern{}

#fnmain(){}

Notaqueactualmenteestafacilidadestaescondidadetráslapuertafeature(link_args)debidoaquenoesunaformasancionadadeefectuarenlazado.Actualmenterutscenvuelveaelenlazadordelsistema(gccenlamayoríadelossistemas,link.exeenMSVC),esporelloquetienesentidoproveerargumentosdelineadecomandoextra,peronosiempreseraesteelcaso.EnelfuturorustcpudierausarLLVMdirectamenteparaenlazarconbibliotecasnativas,escenarioendondelink_argsnotendríasentido.Puedeslograrelmismoefectodelatributolink_argsconelargumento-Clink-argsderustc.

Esaltamenterecomendadonousaresteatributo,yensulugarusarelmasformal#[link(...)]enlosbloquesextern.

EnlazadoestaticoElenlaceestáticoserefiereaelprocesodecrearunasalidaquecontengatodaslasbibliotecasrequeridasyporlotantonorequieraquelasbibliotecasesténinstaladasencadasistemaenelquedeseesusartuproyectocompilado.LadependenciaspurasRustsonenlazadasestáticamentepordefectodemaneraquepuedasusarlasbibliotecasyejecutablescreadossininstalarRustentodoslados.Encontraste,lasbibliotecasnativas(e.jlibcylibm)sonusualmenteenlazadasdemaneradinámica,peroestosepuedecambiaryenlazarlastambiéndemaneraestática.

ElLenguajedeProgramacionRust

323EnlaceAvanzado

Page 324: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

Elenlaceesuntópicomuydependientedeplataforma,yelenlaceestáticopuedenoserposibleentodaslasplataformas.Estasecciónasumeciertafamiliaridadconelenlaceentuplataforma.

LinuxPordefecto,todoslosprogramasenLinuxseenlazaranconlabibliotecalibcdelsistemaenconjuntoconotrogrupodebibliotecas.Veamosunejemploenunamaquinalinuxde64bitsconGCCyglibc(porlejoslalibcmascomúnenLinux):

$catexample.rs

fnmain(){}

$rustcexample.rs

$lddexample

linux-vdso.so.1=>(0x00007ffd565fd000)

libdl.so.2=>/lib/x86_64-linux-gnu/libdl.so.2(0x00007fa81889c000)

libpthread.so.0=>/lib/x86_64-linux-gnu/libpthread.so.0(0x00007fa81867e000)

librt.so.1=>/lib/x86_64-linux-gnu/librt.so.1(0x00007fa818475000)

libgcc_s.so.1=>/lib/x86_64-linux-gnu/libgcc_s.so.1(0x00007fa81825f000)

libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007fa817e9a000)

/lib64/ld-linux-x86-64.so.2(0x00007fa818cf9000)

libm.so.6=>/lib/x86_64-linux-gnu/libm.so.6(0x00007fa817b93000)

Elenlacedinámicoenlinuxpuedeserindeseablesideseasusarlasfacilidadesdelanuevabibliotecaensistemasviejososistemasdestinoquenoposeenlasdependenciasrequeridasparaejecutarelprograma.

Elenlaceestáticoessoportadoatravésdeunalibcalternativa,musl.PuedescompilartuversiondeRustconmuslhabilitadoeinstalarloenundirectoriopersonalizadoconlassiguientesinstrucciones:

ElLenguajedeProgramacionRust

324EnlaceAvanzado

Page 325: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$mkdirmusldist

$PREFIX=$(pwd)/musldist

$

$#Construirmusl

$curl-Ohttp://www.musl-libc.org/releases/musl-1.1.10.tar.gz

$tarxfmusl-1.1.10.tar.gz

$cdmusl-1.1.10/

musl-1.1.10$./configure--disable-shared--prefix=$PREFIX

musl-1.1.10$make

musl-1.1.10$makeinstall

musl-1.1.10$cd..

$du-hmusldist/lib/libc.a

2.2Mmusldist/lib/libc.a

$

$#Construirlibunwind.a

$curl-Ohttp://llvm.org/releases/3.7.0/llvm-3.7.0.src.tar.xz

$tarxfllvm-3.7.0.src.tar.xz

$cdllvm-3.7.0.src/projects/

llvm-3.7.0.src/projects$curlhttp://llvm.org/releases/3.7.0/libunwind-3.7.0.src.tar.xz|tarxJf-

llvm-3.7.0.src/projects$mvlibunwind-3.7.0.srclibunwind

llvm-3.7.0.src/projects$mkdirlibunwind/build

llvm-3.7.0.src/projects$cdlibunwind/build

llvm-3.7.0.src/projects/libunwind/build$cmake-DLLVM_PATH=../../..-DLIBUNWIND_ENABLE_SHARED=0..

llvm-3.7.0.src/projects/libunwind/build$make

llvm-3.7.0.src/projects/libunwind/build$cplib/libunwind.a$PREFIX/lib/

llvm-3.7.0.src/projects/libunwind/build$cd../../../../

$du-hmusldist/lib/libunwind.a

164Kmusldist/lib/libunwind.a

$

$#ConstruirRustconmuslhabilitado

$gitclonehttps://github.com/rust-lang/rust.gitmuslrust

$cdmuslrust

muslrust$./configure--target=x86_64-unknown-linux-musl--musl-root=$PREFIX--prefix=$PREFIX

muslrust$make

muslrust$makeinstall

muslrust$cd..

$du-hmusldist/bin/rustc

12Kmusldist/bin/rustc

AhoraposeesunRustconmuslhabilitado!Ydebidoaquelohemosinstaladoenunprefijopersonalizadonecesitamosasegurarnosdequenuestrosistemapuedaencontrarlosejecutablesybibliotecasapropiadascuandotratemosdeejecutarlo:

$exportPATH=$PREFIX/bin:$PATH

$exportLD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH

Probémoslo!

ElLenguajedeProgramacionRust

325EnlaceAvanzado

Page 326: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

$echo'fnmain(){println!("Hola!");panic!("falla");}'>example.rs

$rustc--target=x86_64-unknown-linux-muslexample.rs

$lddexample

notadynamicexecutable

$./example

Hola!

thread'

'panickedat'failed',example.rs:1

Exito!EstebinariopuedesercopiadoacasicualquiermaquinaLinuxconlamismaarquitecturayserejecutadosinningúnproblema.

cargobuildtambiénpermitelaopción--targetpormediodelacualpuedesconstruirtuscratesnormalmente.Sinembargo,podríasnecesitarrecompilartusbibliotecasnativasconmuslantesdepoderenlazarconellas.

ElLenguajedeProgramacionRust

326EnlaceAvanzado

Page 327: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%PruebasdePuntosdeReferencia

ElLenguajedeProgramacionRust

327PruebasdeRendimiento

Page 328: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%SintaxisdeCajasyPatrones

ElLenguajedeProgramacionRust

328SintaxisBoxyPatones

Page 329: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%PatronesdeSlice

ElLenguajedeProgramacionRust

329PatronesSlice

Page 330: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%ConstantesAsociadas

Conelfeatureassociated_consts,puedesdefinirconstantescomo:

#![feature(associated_consts)]

traitFoo{

constID:i32;

}

implFoofori32{

constID:i32=1;

}

fnmain(){

assert_eq!(1,i32::ID);

}

CualquierimplementadordeFootendráquedefinirID.Sinladefinición:

#![feature(associated_consts)]

traitFoo{

constID:i32;

}

implFoofori32{

}

resultaen

error:notalltraititemsimplemented,missing:`ID`[E0046]

implFoofori32{

}

Unvalorpordefectopuedetambiénserimplementado:

ElLenguajedeProgramacionRust

330ConstantesAsociadas

Page 331: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

#![feature(associated_consts)]

traitFoo{

constID:i32=1;

}

implFoofori32{

}

implFoofori64{

constID:i32=5;

}

fnmain(){

assert_eq!(1,i32::ID);

assert_eq!(5,i64::ID);

}

Comopuedesver,alimplementarFoo,puedesdejarlosinimplementación,comoenelcasodei32.Entoncesesteusaraelvalorpordefecto.Pero,tambiényaligualquecomoeni64,podemosagregarnuestrapropiadefinición.

Lasconstantesasociadasnonecesitansolofuncionancontraits.Unbloqueimplparaunastructounenumestambiénvalido:

#![feature(associated_consts)]

structFoo;

implFoo{

constFOO:u32=3;

}

ElLenguajedeProgramacionRust

331ConstantesAsociadas

Page 332: Tabla de contenido · El Juego de las Adivinanzas La Cena de los Filósofos Rust dentro de otros Lenguajes Rust Efectivo La Pila y el Montículo ... Rust desde el codigo fuente ...

%InvestigacionAcademica

ElLenguajedeProgramacionRust

332InvestigaciónAcadémica