El Libro de Rust (Lenguaje de Programación)

download El Libro de Rust (Lenguaje de Programación)

of 120

description

Este libro te enseñara acerca del Lenguaje de Programación Rust. Rust es un lenguaje de programación de sistemas enfocado en tres objetivos: seguridad, velocidad y concurrencia.

Transcript of El Libro de Rust (Lenguaje de Programación)

  • 1. Introduccin2. PrimerosPasos

    i. InstalandoRustii. Hola,mundo!iii. Hola,Cargo!

    3. AprendeRusti. JuegodeAdivinanzasii. LaCenadelosFilsofosiii. RustDentrodeOtrosLenguajes

    4. RustEfectivoi. LaPilayelMonticuloii. Pruebasiii. CompilacinCondicionaliv. Documentacinv. Iteradoresvi. Concurrenciavii. ManejodeErroresviii. FFIix. BorrowyAsRefx. CanalesdeDistribucin

    5. SintaxisySemnticai. Variablesii. Funcionesiii. TiposPrimitivosiv. Comentariosv. ifvi. ciclosforvii. cicloswhileviii. Pertenenciaix. ReferenciasyPrstamox. TiemposdeVidaxi. Mutabilidadxii. Estructurasxiii. Enumeracionesxiv. Matchxv. Patronesxvi. SintaxisdeMetodosxvii. Vectoresxviii. CadenasdeCaracteresxix. Genricosxx. Rasgosxxi. Dropxxii. ifletxxiii. ObjectosRasgoxxiv. Closuresxxv. SintaxisdeLlamadasaFuncionUniversalxxvi. CajonesyModulosxxvii. `const`y`static`xxviii. Atributos

    Tabladecontenido

    ElLenguajedeProgramacionRust

    2

  • xxix. alias`type`xxx. Conversinentretiposxxxi. TiposAsociadosxxxii. TipossinTamaoxxxiii. OperadoresySobrecargaxxxiv. CoercionesDerefxxxv. Macrosxxxvi. ApuntadoresPlanosxxxvii. `unsafe`6. RustNocturno

    i. PluginsdeCompiladorii. EnsambladorenLineaiii. Nostdlibiv. Intrinsecosv. ItemsdeLenguajevi. ArgumentosdeEnlacevii. PruebasdePuntosdeReferenciaviii. SintaxisdeCajasyPatronesix. PatronesdeSlicex. ConstantesAsociadas

    7. Glosario8. InvestigacionAcademica

    ElLenguajedeProgramacionRust

    3

  • Bienvenido!EstelibroteensearaacercadelLenguajedeProgramacinRust.Rustesunlenguajedeprogramacindesistemasenfocadoentresobjetivos:seguridad,velocidadyconcurrencia.Rustlograestosobjetivossintenerunrecolectordebasura,haciendoloutilparaunnumerodecasosdeusoparaloscualesotroslenguajesnosontanbuenos:embeberenotroslenguajes,programasconrequerimientosespecficosdetiempoyespacio,escrituradecdigodebajonivel,comocontroladoresdedispositivoysistemasoperativos.Rustmejoraporsobreloslenguajesactualesenestenichoatravsdeunnumerodechequeosentiempodecompilacinquenoincurrenningunapenalidadentiempodeejecucin,eliminandoalmismotiempolascondicionesdecarrera.Rusttambinimplementa'abstraccionesconcerocosto',abstraccionesquesesientencomolasdeunlenguajedealtonivel.Aunas,Rustpermitecontrolprecisotalycomounlenguajedebajonivelloharia.

    ElLenguajedeProgramacinRustestadivididoensietesecciones.Estaintroduccineslaprimera.Despusdeesta:

    PrimerosPasos-ConfiguratumaquinaparaeldesarrolloenRust.AprendeRust-AprendeprogramacinenRustatravsdepequeosproyectos.RustEfectivo-ConceptosdealtonivelparaescribirexcelentecdigoRust.SintaxisySemantica-CadapiezadeRust,divididaenpequenospedazos.RustNocturno-Caractersticastodavanodisponiblesenbuildsestables.Glosario-Referenciadelostrminosusadosenellibro.InvestigacinAcadmica-LiteraturaqueinfluencioRust.

    Despusdeleerestaintroduccin,dependiendodetupreferencia,querrsleerAprendeRustoSintaxisySemantica:AprendeRustsiquierescomenzarconunproyectooSintaxisySemntica,siprefierescomenzarporlomaspequeoaprendiendounnicoconceptodetalladamenteantesdemovertealsiguiente.Abundantesenlacescruzadosconectandichaspartes.

    LosarchivosfuentedeloscualesestelibroesgeneradopuedenserencontradosenGithub:github.com/rust-lang/rust/tree/master/src/doc/trpl

    EsRustunlenguajeenelcualestarasinteresado?Examinemosunospequeosejemplodecdigoquedemuestranalgunasdesusfortalezas.

    ElconceptoprincipalquehacenicoaRustesllamadopertenencia(ownership).Consideraestepequeoejemplo:

    fnmain(){letmutx=vec!["Hola","mundo"];}

    Esteprogramacreaununavariablellamadax.ElvalordeestavariableesVec,unvector,quecreamosatravsdeunamacrodefinidaenlabibliotecaestandar.Estamacrosellamavec,lasmacrossoninvocadasconun!.TodoestosiguiendounprincipiogeneralenRust:hacerlascosasexplcitas.Lasmacrospuedenhacercosassignificativamentemascomplejasquellamadasafunciones,esporelloquesonvisualmentedistintas.El!alsoayudatambinalanlisissintctico,haciendolaescrituradeherramientasmasfcil,locualestambinimportante.

    Hemosusadomutparahacerxmutable:EnRustlasvariablesoninmutablespordefecto.Mastardeenesteejemploestaremosmutandoestevector.

    ElLenguajedeProgramacinRust

    Contribuyendo

    UnabreveintroduccinaRust

    ElLenguajedeProgramacionRust

    4Introduccin

  • Esimportatemencionarquenonecesitamosunaanotacindetiposaqui:sibienRustesestaticamentetipado,nonecesitamosanotareltipodeformaexplicita.Rustposeeinferenciadetiposparabalancearelpoderdeeltipadoestaticoconlaverbosidaddelasanotacionesdetipos.

    Rustprefiereasignacindememoriadesdelapilaquedesdeelmontculo:xespuestodirectamenteenlapila.Sinembargo,eltipoVecasignaespacioparaloselementosdelvectorenelmontculo.SinoestasfamiliarizadoconestadistincinpuedesignorarlaporahoraoecharunvistazoLaPilayelMonticulo.Rustcomounlenguajedeprogramacindesistemas,tedalahabilidaddecontrolarcomolamemoriaesasignada,perocomoestamoscomenzandonoestanrelevante.

    AnteriormentemencionamosquelapertenenciaesnuevoconceptoclaveenRust.EnterminologaRust,xeseldueodelvector.Estosignificaquecuandoxsalgadembito,lamemoriaasignadaaelvectorseraliberada.EstoeshechoporelcompiladordeRustdemaneradeterministica,sinlanecesidaddeunmecanismocomounrecolectordebasura.Enotraspalabras,enRust,nohacesllamadasafuncionescomomallocyfreeexplcitamente:elcompiladordeterminademaneraestticacuandosenecesitaasignaroliberarmemoria,einsertaesasllamadasporti.Erraresdehumanos,peroloscompiladoresnuncaolvidan.

    Agreguemosotralineaanuestroejemplo:

    fnmain(){letmutx=vec!["Hola","mundo"];

    lety=&x[0];}

    Hemosintroducidootravariable,y.Enestecaso,yesunareferenciaaelprimerelementodeelvector.LasreferenciasenRustsonsimilaresalosapuntadoresenotroslenguajes,peroconchequeosdeseguridadadicionalesentiempodecompilacin.Lasreferenciasinteractuanconelsistemadepertenenciaatravsdeelprestamo(borrowing),ellastomanprestadoaloqueapuntan,envezdeaduearsedeello.Ladiferenciaesquecuandolareferenciasalgadembito,lamemoriasubyacentenoseraliberada.Desereseelcasoestaramosliberandolamismamemoriadosveces,locualesmalo.

    Agreguemosunaterceralinea.Dichalinealuceinocenteperocausaunerrordecompilacin:

    fnmain(){letmutx=vec!["Hola","mundo"];

    lety=&x[0];

    x.push("foo");}

    pushesunmetodoenlosvectoresqueagregaunelementoalfinaldelvector.Cuandotratamosdecompilarelprogramaobtenemosunerror:

    error:cannotborrow`x`asmutablebecauseitisalsoborrowedasimmutablex.push("foo");^note:previousborrowof`x`occurshere;theimmutableborrowpreventssubsequentmovesormutableborrowsof`x`untiltheborrowendslety=&x[0];^note:previousborrowendsherefnmain(){

    }^

    ElLenguajedeProgramacionRust

    5Introduccin

  • Uff!ElcompiladordeRustalgunasvecespuedeproporcionarerroresbiendetalladosyestavezunadeellas.Comoelerrorloexplica,mientrashacemoslavariablemutablenopodemosllamarapush.Estoesporqueyatenemosunareferenciaaunelementodelvector,y.Mutaralgomientrasexisteunareferenciaaelloespeligroso,porquepodemosinvalidarlareferencia.Enestecasoenespecifico,cuandocreamoselvector,solohemosasignadoespacioparadoselementos.Agregaruntercerosignificaraasignarunnuevosegmentodememoriaparatodosloselementos,copiartodoslosvaloresanterioresyactualizarelapuntadorinternoaesamemoria.Todoesoestabien.Elproblemaesqueynoseriaactualizado,generandounpunterocolgante.Locualestamal.Cualquierusodeyseriaunerrorenestecaso,yelcompiladornoshaprevenidodeello.

    Entonces,comoresolvemosesteproblema?Haydosenfoquesquepodramostomar.Elprimeroeshacerunacopiaenlugardeunareferencia:

    fnmain(){letmutx=vec!["Hola","mundo"];

    lety=x[0].clone();

    x.push("foo");}

    Rusttienepordefectosemnticademovimiento,entoncessiqueremoshacerunacopiadealgunadata,llamamoselmtodoclone().Enesteejemployyanoesunareferenciaaelvectoralmacenadoenx,sinounacopiadesuprimerelemento,"Hola".Debidoaquenotenemosunareferencianuestropush()funcionaperfectamente.

    Sirealmentequeremosunareferencia,necesitamosotraopcin:asegurarnosdequenuestrareferenciasalgadembitoantesquetratamosdehacerlamutacin.Deestamanera:

    fnmain(){letmutx=vec!["Hola","mundo"];

    {lety=&x[0];}

    x.push("foo");}

    Conelparadicionaldellaveshemoscreadounmbitointerno.ysaldrdembitoantesquellamemosapush(),entoncesnohayproblema.

    Esteconceptodepertenencianoessolobuenoparaprevenirpunteroscolgantes,sinounconjuntoenterodeproblemas,comoinvalidacindeiteradores,concurrenciaymas.

    ElLenguajedeProgramacionRust

    6Introduccin

  • EstaprimeraseccindellibrotepondrandandoenRustysusherramientas.Primero,instalaremosRust.Despus,elclsicoprogramaHolaMundo.Finalmente,hablaremosdeCargo,elsistemadeconstruccinymanejadordepaquetesdeRust.

    PrimerosPasos

    ElLenguajedeProgramacionRust

    7PrimerosPasos

  • ElprimerpasoparausarRustesinstalarlo!ExistenunnumerodemanerasparainstalarRust,perolamasfcilesusarelscriptrustup.SiestasenLinuxounaMac,todoloquenecesitashaceres(sinescribirlos$s,soloindicaneliniciodecadacomando):

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

    Siestaspreocupadoacercadelainseguridadpotencialdeusarcurl|sh,porfavorcontinualeyendoyvenuestrodisclaimer.Sientetelibredeusarlaversiondedospasosdelainstalacinyexaminarnuestroscript:

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

    SiestasenWindows,porfavordescargaelinstaladorde32bitsoelinstaladorde64bitsyejecutalo.

    SidecidesqueyanoquieresmasRust,estaremosunpocotristes,peroestabienningnlenguajedeprogramacinesparatodoelmundo.Simplementeejecutaelscriptdedesinstalacin:

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

    SiusasteelinstaladordeWindowssimplementevuelveaejecutarel.msiyestetedaralaopcindedesinstalar.

    Algunaspersonas,conmuchoderecho,sevenperturbadascuandolesdicesquedebencurl|sh.Bsicamente,alhacerlo,estasconfiandoenquelabuenagentequemantieneRustnovaahackeartucomputadoryhacercosasmalas.Esoesbueninstinto!SieresunadeesaspersonasporfavorechaunvistazoaladocumentacinacercadecompilarRustdesdeelcodigofuente,olapaginaoficialdedescargasdebinarios.

    Ah,tambindebemosmencionarlasplataformassoportadasoficialmente:

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

    NosotrosprobamosRustextensivamenteendichasplataformas,yalgunasotraspocas,comoAndroid.Estassonlasquegarantizanfuncionardebidoaquetienenlamayorcantidaddepruebas.

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

    SiyatienesRustinstalado,puedesabrirunaconsolayescribir:

    $rustc--version

    InstalandoRust

    Desintalando

    ElLenguajedeProgramacionRust

    8InstalandoRust

  • Deberiasverelnumerodeversin,hashdelcommit,fechadelcommitylafechadecompilacin:

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

    Silohasvisto,Rusthasidoinstaladosatisfactoriamente!Felicitaciones!

    Esteinstaladortambininstalaunacopiadeladocumentacinlocalmenteparaquepuedasleerlaaunestandodesconectado.EnsistemasUNIX,/usr/local/share/doc/rusteslalocacin.EnWindows,eseneldirectorioshare/doc,dentrodedondeseaquehayasinstaladoRust.

    Sino,hayunnumerodelugaresenlosquepuedesobtenerayuda.ElmasfcileselcanaldeIRC#rustenirc.mozilla.org,alcualpuedesaccederconMibbit.SigueeseenlaceyestarashablandoconRusteros(atontoapodoqueusamosentrenosotros),yteayudaremos.Otrosexcelentesrecursossonelforodeusuarios,yStackOverflow.

    ElLenguajedeProgramacionRust

    9InstalandoRust

  • AhoraquehasinstaladoRust,escribamostuprimerprograma.EstradicinquetuprimerprogramaencualquierlenguajeseaunoqueimprimaeltextoHola,mundo!alapantalla.Lobuenodecomenzarconunprogramatansimpleesqueverificasnosoloqueelcompiladorestainstalado,sinoqueestafuncionando.Imprimirinformacinalapantallaesunacosamuycomn.

    Laprimeracosaquedebemoshacerescrearunarchivoendondeponernuestrocdigo.Amimegustacrearundirectorioproyectosenmidirectoriodeusuarioymantenertodosmisproyectosall.ARustnoleimportadondeelcdigoreside.

    Estollevaencuestinaotroasuntoquedebemosaclarar:estaguaasumirqueposeesunafamiliaridadbsicaconlalineadecomandos.Rustnodemandanadaconrespectoatusherramientasdeedicinodondevivetucdigo.SiprefieresunIDEalainterfazdelineadecomandos,probablementedeberasecharunvistazoaSolidOak,odondeseaquelospluginsestenparatuIDEfavorito.Existenunnumerodeextensionesdecalidadvariadaendesarrolloporlacomunidad.ElequipodetrsdeRusttambinpublicapluginsparavarioseditores.ConfigurartueditoroIDEescapadellosobjetivosdeestetutorial,chequealadocumentacinparatuconfiguracinenespecifico.

    Dichoesto,creemosundirectorioennuestrodirectoriodeproyectos.

    $mkdir~/proyectos$cd~/proyectos$mkdirhola_mundo$cdhola_mundo

    SiestasenWindowsynoestasusandoPowerShell,el~podranofuncionar.Consultaladocumentacionespecificaparatuterminalparamayordetalle.

    Creemosunnuevoarchivodecdigofuente.Llamaremosmain.rsanuestroarchivo.LosarchivosRustterminanconlaextensin.rs.Siestasusandomasdeunapalabraentunombredearchivo,usaunsubguion:hola_mundo.rsenvezdeholamundo.rs.

    Ahoraquetienestuarchivoabiertoescribeestoenel:

    fnmain(){println!("Hola,mundo!");}

    Guardaloscambiosenelarchivo,yescribelosiguienteenlaventanadetuterminal:

    $rustcmain.rs$./main#omain.exeenWindowsHola,mundo!

    Exito!Ahoraveamosquehapasadoendetalle.

    fnmain(){

    }

    EstaslineasdefinenunafuncionenRust.Lafuncinmainesespecial:eselprincipiodetodoprogramaRust.Laprimeralineadice:"Estoydeclarandounafuncinllamadamainlacualnorecibeargumentosynoretornanada."Siexistieran

    Hola,mundo!

    ElLenguajedeProgramacionRust

    10Hola,mundo!

  • argumentos,estosirandentrodeparntesis((and)),ydebidoaquenoestamosretornandonadadeestafuncin,podemosomitireltipoderetornocompletamente.Llegaremosaestomasadelante.

    Tambinnotarasquelafuncinestaenvueltaenllaves({and}).Rustrequieredichasllavesdelimitandotodosloscuerposdefuncin.Estambinconsideradobuenestilocolocarlallavedeaperturaenlamismalineadeladeclaracindelafuncin,conunespaciointermedio.

    Losiguienteesestalinea:

    println!("Hola,mundo!");

    Estalineahacetodoeltrabajoennuestropequeoprograma.Hayunnumerodedetallesquesonimportantesaqu.Elprimeroesqueestaidentadoconcuatroespacios,notabulaciones.Porfavorconfiguratueditorainsertarcuatroespaciosconlateclatab.Proveemosalgunosconfiguracionesdeejemploparavarioseditores.

    Elsegundopuntoeslaparteprintln!().EstoesllamaraunamacroRustmacro,queescomosehacemetaprogramacinenRust.Siestofueseencambiounafuncin,luciriaasi:println().Paranuestrosefectos,nonecesitamospreocuparnosacercadeestadiferencia.Solosaberquealgunasvecesveras!,yqueestosignificaqueestasllamandoaunamacroenvezdeunafuncinnormal.Rustimplementaprintln!comounamacroenvezdecomounafuncinporbuenasrazones,peroesoesuntpicoavanzado.Unaultimacosapormencionar:LasmacrosenRustsondiferentesdelasmacrosenC,silashasusado.Noestesasustadodeusarmacros.Llegaremosalosdetalleseventualmente,porahorasimplementedebesconfiarennosotros.

    Acontinuacin,"Hola,mundo!"esunacadenadecaracteres.Lascadenasdecaracteressonuntpicosorprendentementecomplejoenlenguajesdeprogramacindesistemas,yestaconcretamenteesunacadenadecarateresasigandastaticamente.Sitegustarialeeracercadeasignaciondememoria,echaunvistazoalapilayelmontculo,peroporahoranonecesitashacerlosilonodeseas.Pasamosestacadenadecaracterescomounargumentoaprintln!quienasuvezimprimelacadenadecaracteresalapantalla.Facil!

    Finalmente,lalineaterminaconunpuntoycoma(;).Rustesunlenguajeorientadoaexpresiones,loquesignificaquelamayoradelascosassonexpresiones,envezdesentencias.El;seusaparaindicarquelaexpresinhaterminado,yquelasiguienteestalistaparacomenzar.LamayoradelaslineasdecdigoenRustterminanconun;.

    Finalmente,compilaryejecutarnuestroprograma.Podemoscompilarconnuestrocompiladorrustcpasandoleelnombredenuestroarchivodecdigofuente:

    $rustcmain.rs

    Estoessimilaragccorclang,siprovienesdeCoC++.Rustemitiraunbinarioejecutable.Puedesverloconls:

    $lsmainmain.rs

    OenWindows:

    $dirmain.exemain.rs

    Haydosarchivos:nuestrocdigofuente,conlaextensin.rs,yelejecutable(main.exeenWindows,mainenlosdems)

    ElLenguajedeProgramacionRust

    11Hola,mundo!

  • $./main#omain.exeenWindows

    LoanteriorimprimenuestrotextoHola,mundo!anuestraterminal.

    SiprovienesdeunlenguajedinmicocomoRuby,PyhtonoJavascript,probablementenoestsacostumbradoaverestosdospasoscomoseparados.Rustesunlenguajecompilado,locualsignificaquepuedescompilartuprograma,darseloaalguienmas,yestenonecesitatenerRustinstalado.Silesdasaalguienunarchivo.rbo.pyo.js,estenecesitatenerunaimplementacindeRuby/Python/JavaScript,perosolonecesitasuncomandoparaambos,compilaryejecutartuprograma.Todoesacercadebalanceentreventajas/desventajaseneldiseodelenguajes,yRusthaelegido.

    Felicitaciones,HasescritooficialmenteunprogramaRust.EsoteconvierteenunprogramadorRust!Bienvenido.

    Acontinuacinmegustarapresentarteotraherramienta,Cargo,elcualesusadoparaescribirprogramasRustparaelmundoreal.Solousarrustcestabienparacosassimples,peroamedidaquetuproyectocrece,necesitarasalgoqueteayudeaadministrartodaslasopcionesqueestetiene,ascomohacerfcilcompartirelcodigoconotraspersonasyproyectos.

    ElLenguajedeProgramacionRust

    12Hola,mundo!

  • CargoesunaherramientaquelosRusterosusancomoayudaparaadministrarsusproyectosRust.Cargoestaactualmenteenestadopre-1.0,ydebidoaelloestodavauntrabajoenproceso.SinembargoyaeslosuficientementebuenoparamuchosproyectosRust,yseasumequelosproyectosRustusaranCargodesdeelprincipio.

    Cargoadministratrescosas:lacompilacindetucdigo,descargadelasdependenciasquetucdigonecesita,ylacompilacindedichasdependencias.Enprimerainstanciatucdigonotendrningunadependencia,esporelloqueestaremosusandosololaprimerapartedelafuncionalidaddeCargo.Eventualmente,agregaremosmas.DebidoaquecomenzamosusandoCargodesdeelprincipioserafcilagregardespus.

    SihasinstaladoRustatravsdelosinstaladoresoficialesentoncesdeberastenerCargo.SihasinstaladoRustdealgunaotramanera,podrasecharunvistazoaelREADMEdeCargoparainstruccionesespecificasacercadecomoinstalarlo.

    ConvirtamosHolaMundoaCargo.

    ParaCarguificarnuestroproyecto,necesitamosdoscosas:CrearunarchivodeconfiguracinCargo.toml,ycolocarnuestroarchivodecdigofuenteenellugarcorrecto.Hagamosesaparteprimero:

    $mkdirsrc$mvmain.rssrc/main.rs

    Notaquedebidoaqueestamoscreandounejecutable,usamosmain.rs.Siquisiramoscrearunabiblioteca,deberamosusarlib.rs.Locacionespersonalizadasparaelpuntodeentradapuedenserespecificadasconunaclave[[[lib]]or[[bin]]]crates-customenelarchivoTOMLdescritoacontinuacin.

    Cargoesperaquetusarchivosdecdigofuenteresidaneneldirectoriosrc.Estodejaelnivelrazparaotrascosas,comoREADMEs,informacindelicencias,ytodoaquellonorelacionadocontucdigo.Cargonosayudaamantenernuestrosproyectosagradablesyordenados.Unlugarparatodo,ytodoensulugar.

    Acontinuacin,nuestroarchivodeconfiguracin:

    $editorCargo.toml

    Aseguratetetenerestenombrecorrecto:necesitaslaCmayuscula!

    Colocaestodentro:

    [package]

    name="hola_mundo"version="0.0.1"authors=["Tunombre"]

    EstearchivoestaenformatoTOML.Dejemosqueseaelmismoquienseexplique:

    ElobjetivodeTOMLesserunformatodeconfiguracinminimofacildeleerdebidoaunasemnticaobvia.TOMLestadiseadoparamapeardeformain-ambiguaaunatablahash.TOMLdeberaserfcildeconvertiren

    Hola,Cargo!

    MigrandoaCargo

    ElLenguajedeProgramacionRust

    13Hola,Cargo!

  • estructurasdedatosenunaampliavariedaddelenguajes.

    TOMLesmuysimilaraINI,peroconalgunasbondadesextra.

    Unavezquetengasestearchivoessulugar,deberamosestarlistosparacompilar!Pruebaesto:

    $cargobuildCompilinghola_mundov0.0.1(file:///home/tunombre/proyectos/hola_mundo)$./target/debug/hola_mundoHola,mundo!

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

    $cargorunRunning`target/debug/hola_mundo`Hola,mundo!

    Ntesequenoreconstruimoselproyectoestavez.Cargodeterminoquenohabamoscambiadoelarchivodecdigofuente,asquesimplementeejecutoelbinario.Sihubiremosrealizadounamodificacin,deberamoshaberlovistohaciendolosdospasos:

    $cargorunCompilinghola_mundov0.0.1(file:///home/tunombre/proyectos/hola_mundo)Running`target/debug/hola_mundo`Hola,mundo!

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

    Cuandonuestroproyectoestafinalmentelistoparalaliberacion,puedesusarcargobuild--releaseparacompilarloconoptimizaciones.

    TambinhabrasnotadoqueCargohacreadounarchivonuevo:Cargo.lock.

    [root]name="hola_mundo"version="0.0.1"

    EstearchivoesusadoporCargoparallevarelcontroldelasdependenciasusadasentuaplicacin.Porahora,notenemosninguna,yestaunpocodisperso.Nuncadeberasnecesitartocarestearchivoportucuenta,solodejaaCargomanejarlo.

    Esoestodo!Hemosconstruidosatisfactoriamentehola_mundoconCargo.Aunquenuestroprogramaseasimple,estausandogranpartedelasherramientasrealesqueusarasporelrestodetucarreraconRust.PuedesasumirqueparacomenzarvirtualmentecontodoproyectoRustharslosiguiente:

    $gitclonealgunaurl.com/foo$cdfoo$cargobuild

    ElLenguajedeProgramacionRust

    14Hola,Cargo!

  • Notienesquepasarportodoeseprocesocompletocadavezquequierascomenzarunproyectonuevo!Cargoposeelahabilidaddecrearundirectorioplantillaenelcualpuedescomenzaradesarrollarinmediatamente.

    ParacomenzarunproyectonuevoconCargo,usamoscargonew:

    $cargonewhola_mundo--bin

    Estamospasando--binporqueestamoscreandounprogramabinario:siestuviramoscreandounabiblioteca,loomitiramos.

    EchemosunvistazoaloqueCargohageneradoparanosotros:

    $cdhola_mundo$tree..Cargo.tomlsrcmain.rs

    1directory,2files

    Sinotieneselcomandotreeinstalado,probablementepodrasobtenerlomedianteelmanejadordepaquetesdetudistribucin.Noesnecesario,peroesciertamentetil.

    Estoestodoloquenecesitasparacomenzar.PrimeroveamosnuestroCargo.toml:

    [package]

    name="hola_mundo"version="0.0.1"authors=["TuNombre"]

    Cargoarellenadoestearchivoconvalorespordefectobasadoenlosargumentosqueleproporcionasteytuconfiguracinglobalgit.PodriasnotartambienqueCargohainicializadoeldirectoriohola_mundocomounrepositoriogit.

    Aquiestaelcontenidodesrc/main.rs:

    fnmain(){println!("Hola,mundo!");}

    Cargohageneradoun"Hola,mundo!"paranosotros,yaestaslistoparaempezaracodear.Cargoposeesupropiaguialacualcubretodassuscaractersticasconmuchamasprofundidad.

    Ahoraquehemosaprendidolasherramientas,comencemosenrealidadaaprendermasdeRustcomolenguaje.EstoeslabsequeteservirbienporelrestodetutiempoconRust.

    Tienesdosopciones:SumergirteenunproyectoconAprendeRust,ocomenzardesdeelfondoytrabajarhaciaarribaconSintaxisySemntica.ProgramadoresdesistemasmasexperimentadosprobablementepreferiranAprendeRust,mientrasqueaquellosprovenientesdelenguajesdinamicospodriantambiendisfrutarlo.Gentediferenteaprendediferente!Escojeloquefuncionemejorparati.

    UnProyectoNuevo

    ElLenguajedeProgramacionRust

    15Hola,Cargo!

  • ElLenguajedeProgramacionRust

    16Hola,Cargo!

  • Bienvenido!EstaseccintieneunospocostutorialesqueteenserananRustatravsdelaconstruccindeproyectos.Obtendrsununavisingeneral,perotambinleecharemosunvistazoalosdetalles.

    Siprefieresunaexperienciamasalestilodeabajohaciaarriba,echaunvistazoaSintaxisySemantica.

    AprendeRust

    ElLenguajedeProgramacionRust

    17AprendeRust

  • Paranuestroprimerproyecto,implementaremosunproblemaclsicodeprogramacinparaprincipiantes:unjuegodeadivinanzas.Comofuncionaeljuego:Nuestroprogramageneraraunnumeroenteroaleatorioentreunoycien.Nospediraqueintroduzcamosunacorazonada.Despuesdehaberproporcionadonuestronumero,estenosdirsiestuvimosmuypordebajoymuyporencima.Unavezqueadivinemoselnumerocorrecto,nosfelicitara.Suenabien?

    Creemosunnuevoproyecto.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"]

    Cargoobtieneestainformacindetuentorno.Sinoestacorrecta,corrigela.

    Finalmente,CargohageneradounHola,mundo!paranosotros.Echaunvistazoasrc/main.rs:

    fnmain(){println!("Hello,world!");}

    TratemosdecompilarloqueCargonoshaproporcionado:

    $cargobuildCompilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

    Excelente!Abretusrc/main.rsotravez.Estaremosescribiendotodonuestrocodigoenestearchivo.

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

    $cargorunCompilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)Running`target/debug/adivinanzas`Hola,mundo!

    JuegodeAdivinanzas

    ConfiguracinInicial

    ElLenguajedeProgramacionRust

    18JuegodeAdivinanzas

  • Grandioso!Elcomandorunesmuytilcuandonecesitasiterarrapidoenunproyecto.Nuestrojuegoesunodeesosproyectos,necesitaremosprobarrapidamentecadaiteracinantesdemovernosalasiguiente.

    Probemoslo!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.

    usestd::io;

    Necesitaremosrecibirentradadelusuario,paraluegoimprimirelresultadocomosalida.Debidoaestonecesitamoslabibliotecaiodelabibliotecaestandar.Rustsoloimportaunaspocascosasparatodoslosprogramas,esteconjuntodecosassedenominapreludio.Sinoestaenelpreludiotendrsquellamarlodirectamenteatravesdeuse.

    fnmain(){

    Comohasvistoconanterioridad,lafuncinmain()eselpuntodeentradaatuprograma.Lasintaxisfndeclaraunanuevafuncin,los()sindicanquenohayargumentosy{comienzaelcuerpodelafuncin.Debidoaquenoincluimosuntipoderetorno,seasumeser()unatuplavaca.

    println!("Adivinaelnumero!");

    println!("Porfavorintroducetucorazonada.");

    Anteriormenteaprendimosqueprintln!()esunamacroqueimprimeunacadenadecaracteresalapantalla.

    letmutcorazonada=String::new();

    Ahoranosestamosponiendointeresantes!Hayunmontndecosaspasandoenestapequealinea.Laprimeracosasanotaresqueesunasentencialet,usadaparacrearvariables.Tienelaforma:

    letfoo=bar;

    ProcesandounIntentodeAdivinanza

    ElLenguajedeProgramacionRust

    19JuegodeAdivinanzas

  • Estocrearaunanuevavariablellamadafoo,ylaenlazaraalvalorbar.Enmuchoslenguajes,estoesllamadounavariableperolasvariablesdeRusttienenunpardetrucosbajolamanga.

    Porejemplo,sonimmutablespordefecto.Esporelloquenuestroejemplousamut:estohaceunbindingmutable,envezdeinmutable.letnosolotomaunnombredelladoizquierdo,letaceptaunpatrn.Usaremoslospatronesunpocomastarde.Essuficienteporahorausar:

    letfoo=5;//inmutable.letmutbar=5;//mutable

    Ah,//iniciauncomentario,hastaelfinaldelalinea.Rustignoratodoencomentarios

    Entoncessabemosqueletmutcorazonadaintroducirunbindingmutablellamadocorazonada,perotenemosqueveralotroladodel=parasaberaqueestasiendoasociado:String::new().

    Stringesuntipodecadenadecaracter,proporcionadoporlabibliotecaestandar.UnStringesunsegmentodetextocodificadoenUTF-8capazdecrecer.

    Lasintaxis::new()usa::porqueesunafuncinasociadadeuntipoparticular.EsdecirestaasociadaconStringensimismo,envezdeconunainstaciaenparticulardeString.Algunoslenguajesllamanaestounmetodoestatico.

    Estafuncionesllamadanew(),porquecreaunnuevoStringvacio.Encontrarasunafuncinnew()enmuchostipos,debidoaqueesunnombrecomnparalacreacindeunnuevovalordealguntipo.

    Continuemos:

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

    Otromonton!Vallamospiezaporpieza.Laprimeralineatienedospartes.Heaquilaprimera:

    io::stdin()

    Recuerdascomousamosuseenstd::ioenlaprimeralineadenuestroprograma?Ahoraestamosllamandounafuncinasociadaenstd::io.Denohaberusadousestd::io,pudimoshaberescritoestalineacomostd::io::stdin().

    Estafuncinenparticularretornaunhandlealaentradaestndardetuterminal.Masespecificamente,unstd::io::Stdin.

    Lasiguienteparteusaradichohandleparaobtenerentradadelusuario:

    .read_line(&mutcorazonada)

    Aqui,llamamoselmetodoread_line()ennuestrohandle.Losmetodossonsimilaresalasfuncionesasociadas,perosoloestandisponiblesenunainstanciaenparticulardeuntipo,envezdeeneltipoensi.Tambinestamospasandounargumentoaread_line():&mutcorazonada.

    Recuerdascuandocreamoscorazonada?Dijimosqueeramutable.Sinembargoread_linenoaceptaunStringcomoargumento:aceptaun&mutString.Rustposeeunacaracteristicallamadareferencias(references),lacualpermitetenermultiplesreferenciasaunapiezadedata,deestamanerasereducelanecesidaddecopiado.Lasreferenciassonunacaracteristicacompleja,debidoaqueunodelospuntosdeventamasfuertesdeRustesacercadecuanfcilyseguroes

    ElLenguajedeProgramacionRust

    20JuegodeAdivinanzas

  • usarreferencias.Porahoranonecesitamossabermuchodeesosdetallesparafinalizarnuestroprograma.Todoloquenecesitamossaberporelmomentoesquealigualquelosbindingsletlasreferenciassoninmutablespordefecto.Comoconsecuencianecesitamosescribir&mutcorazonadaenvezde&corazonada.

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

    Todavianohemosterminadoconestalinea.Sibienesunasolalineadetexto,essololaprimerapartedeunalinealogicadecdigocompleta:

    .ok().expect("Fallolecturadelinea");

    Cuandollamasaunmetodoconlasintaxis.foo()puedesintroducirunsaltodelineayotroespacio.Estoteayudaadividirlineaslargas.Pudimoshaberescrito:

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

    Peroesoesmasdifcildeleer.Asquelohemosdivididoentreslineasparatresllamadasametodo.Yahemoshabladoderead_line(),peroqueacercadeok()yexpect()?Bueno,yamencionamosqueread_line()colocalaentradadelusuarioenel&mutStringqueleproprocionamos.Perotambienretornaunvalor:enestecasounio::Result.RustposeeunnumerodetiposllamadosResultensubibliotecaestandar:unResultgenerico,yversionesespecificasparasub-bibliotecas,comoio::Result.

    ElpropositodeesosResultescodificarinformacindemanejodeerrores.ValoresdeltipoResulttienenmetodosdefinidosenellos.Enestecasoio::Resultposeeunmetodook(),quesetraduceenqueremosasumirqueestevaloresunvalorexitoso.Sino,descartalainformacinacercadelerror.Porquedescartarlainformacinacercadelerror?,paraunprogramabsico,queremossimplementeimprimirunerrorgenerico,cualquierproblemaquesignifiquequenopodamoscontinuar.Elmetodook()retornaunvalorquetieneotrometododefinitoenel:expect().Elmetodoexpect()tomaelvalorenelcualesllamadoysinoesunvalorexitoso,hacepanicopanic!conunmensajequelehemosproporcionado.Unpanic!comoestecausaraqueelprogramatengaunasalidaabrupta(crash),mostrandodichomensaje.

    Siquitamoslasllamadasaesosdosmetodos,nuestroprogramacompilara,peroobtendremosunaadvertencia:

    $cargobuildCompilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)src/main.rs:10:5:10:44warning:unusedresultwhichmustbeused,#[warn(unused_must_use)]onbydefaultsrc/main.rs:10io::stdin().read_line(&mutcorazonada);^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    RustnosadviertequenohemosusadoelvalorResult.Estaadvertenciavienedeunaanotacinespecialquetieneio::Result.Rustestatratandodedecirtequenohasmanejadounposibleerror.Lamaneracorrectadesuprimirelerrores,enefectoescribirelcdigoparaelmanejodeerroes.Porsuerte,sisoloqueremosterminarlaejecucindelprogramadehaberunproblema,podemosusarestosdospequeosmetodos.Sipudieramosrecuperarnosdelerrordealgunamanera,hariamosalgodiferente,perodejemosesoparaunproyectofuturo.

    Solonosquedaunalineadeesteprimerejemplo:

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

    ElLenguajedeProgramacionRust

    21JuegodeAdivinanzas

  • Estalineaimprimelacadenadecaracteresenlaqueguardamosnuestraentrada.Los{}ssonmarcadoresdeposicin,esporelloquepasamosadivinanzacomoargumento.Dehaberhabidomultiples{}s,debiamoshaberpasadomultiplesargumentos:

    letx=5;lety=10;

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

    Fcil.

    Decualquiermodo,eseeseltour.Podemosejecutarloconcargorun:

    $cargorunCompilingguessing_gamev0.1.0(file:///home/tu/proyectos/adivinanzas)Running`target/debug/adivinanzas`Adivinaelnumero!Porfavorintroducetucorazonada.6Tucorazonadafue:6

    Enhorabuena!Nuestraprimerapartehaterminado:podemosobtenerentradadeltecladoeimprimirladevuelta.

    Acontinuacinnecesitamosgenerarunnumerosecreto.Rusttodavanoincluyeunafuncionalidaddenumerosaleatoriosenlabibliotecaestndar.Sinembargo,elequipodeRustproveeuncraterand.UncrateesunpaquetedecdigoRust.Nosotroshemosestadoconstruyendouncratebinaro,elcualesunejecutable.randesuncratebiblioteca,quecontienecodigoaserusadoporotrosprogramas.

    UsarcratesexternosesdondeCargorealmentebrilla.Antesquepodamosescribircdigoquehagausoderand,debemosmodificarnuestroarchivoCargo.toml.Abrelo,yagregaestaslineasalfinal:

    [dependencies]

    rand="0.3.0"

    Laseccin[dependencies]deCargo.tomlescomolaseccin[package]:todoloquelesigueespartedeella,hastaquelasiguienteseccincomience.Cargousalaseccindedependenciasparasaberencualescratesexternosdependemos,asicomolasversionesrequeridas.Enestecasohemosusadolaversin0.3.0.CargoentiendeVersionadoSemantico,queesunestandarparalasescrituradenumerosdeversin.Siquisieramosusarlaultimaversionpodriamoshaberusado*ounrangodeversiones.LadocumentacindeCargocontienemasdetalles.

    Ahora,sincambiarnadaennuestrocdigo,construyamosnuestroproyecto:

    $cargobuildUpdatingregistry`https://github.com/rust-lang/crates.io-index`Downloadingrandv0.3.8Downloadinglibcv0.1.6Compilinglibcv0.1.6Compilingrandv0.3.8Compilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

    Generandounnumerosecreto

    ElLenguajedeProgramacionRust

    22JuegodeAdivinanzas

  • (Podriasverversionesdiferentes,porsupuesto.)

    Unmontndesalidamas!Ahoraquetenemosunadependenciaexterna,Cargodescargadelregistrolasultimasversionesdetodo,locualpuedecopiardatosdesdeCrates.io.Crates.ioesdondelaspersonasdelecosistemaRustpublicansusproyectosopensourceparaqueotroslosusen.

    Despuesdeactualizarelregistro,Cargochequeanuestrasdependencias(en[dependencies])ylasdescargadenotenerlastodava.Enestecasosolodijimosquequeriamosdependerenrand,ytambienobtuvimosunacopiadelibc.Estoesdebidoaqueranddependeasuvezdelibcparafuncionar.Despuesdedescargarlasdependencias,Cargolascompila,paradespuescompilarnuestrocdigo.

    Siejecutamoscargobuild,obtendremosunasalidadiferente:

    $cargobuild

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

    $cargobuildCompilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)

    Entonces,lehemosdichoaCargoquequeriamoscualquierversin0.3.xderand,yestedescargolaultimaversinparaelmomentodelaescrituradeestetutorial,v0.3.8.Peroquepasacuandolasiguienteversinv0.3.9seapublicadaconunimportantebugfix?Sibienrecibirbugfixesesimportante,quepasasi0.3.9contieneunaregresionquerompenuestrocodigo?

    LarespuestaaesteproblemaeselarchivoCargo.lock,archivoqueencontrarasentudirectoriodeproyecto.Cuandoconstruyestuproyectoporprimeravez,cargodeterminatodaslasversionesquecoincidencontuscriteriosylasescribeenelarchivoCargo.lock.Cuandoconstruyestuproyectoenelfuturo,CargonotaraqueunarchivoCargo.lockexiste,yusaralasversionesespecificadasenelmismo,envezdehacertodoeltrabajodedeterminarlasversionesotravez.Estotepermitetenerunaconstruccinreproducibledemaneraautomatica.Enotraspalabras,nosquedaremosen0.3.8hastaquesubamosdeversiondemaneraexplicita,deigualmaneraloharlagenteconlaquehemoscompartidonuestrocdigo,graciasalarchivoCargo.lock.

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

    HaymuchomasquedeciracercadeCargoysuecosistema,peroporahora,esoestodoloquenecesitamossaber.Cargohacerealmentefcilreusarbibliotecas,ylosRusterostiendenaescribirproyectospequenosloscualesestanconstruidosporunconjuntodepaquetesmaspequeos.

    Hagamosusoahoraderand.Heaquinuestrosiguientepaso:

    externcraterand;

    usestd::io;userand::Rng;

    ElLenguajedeProgramacionRust

    23JuegodeAdivinanzas

  • 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);}

    Laprimeracosaquehemoshechoescambiarlaprimeralinea.Ahoradiceexterncraterand.Debidoaquedeclaramosrandennuestraseccin[dependencies],podemosusarexterncrateparahacerlesaberaRustqueestaremoshaciendousoderand.Estoesequivalenteaunuserand;,demaneraquepodamoshacerusodeloqueseadentrodelcraterandatravesdelprefijorand::.

    Despus,hemosagregadootralineause:userand::Rng.Enunosmomentosestaremoshaciendousodeunmetodo,yestorequierequeRngestedisponibleparaquefuncione.Laideabasicaeslasiguiente:losmetodosestandentrodealgollamadotraits(Rasgos),yparaqueelmetodofuncionenecesitaqueeltraitestedisponible.ParamayoresdetallesdirigetealaseccinRasgos(Traits).

    Haydoslineasmasenelmedio:

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

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

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

    Lasegundalineasoloimprimeelnumerosecreto.Estoestilmietrasdesarrollamosnuestroprograma,demaneratalquepodamosprobarlo.Estaremoseliminandoestalineaparalaversionfinal.Noesunjuegosiimprimelarespuestajustocuandoloinicias!

    Tratadeejecutarelprogramaunaspocasveces:

    $cargorunCompilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)Running`target/debug/adivinanzas`Adivinaelnumero!Elnumerosecretoes:7Porfavorintroducetucorazonada.4Tucorazonadafue:4$cargorunRunning`target/debug/adivinanzas`Adivinaelnumero!Elnumerosecretoes:83Porfavorintroducetucorazonada.5Tucorazonadafue:5

    ElLenguajedeProgramacionRust

    24JuegodeAdivinanzas

  • Gradioso!Acontinuacion:comparemosnuestraadivinanzaconelnumerosecreto.

    Ahoraquetenemosentradadelusuario,comparemoslaadivinanzaconnuestronumerosecreto.Heaquinuestrosiguientepaso,aunquetodavianofuncionacompletamente:

    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!("Muypequeo!"),Ordering::Greater=>println!("Muygrande!"),Ordering::Equal=>println!("Hazganado!"),}}

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

    matchcorazonada.cmp(&numero_secreto){Ordering::Less=>println!("Muypequeo!"),Ordering::Greater=>println!("Muygrande!"),Ordering::Equal=>println!("Hazganado!"),}

    Elmetodocmp()puedeserllamadoancualquiercosaquepuedasercomparada,estetomaunareferenciaalacosaconlacualquierascomparar.RetornaeltipoOrderingquehicimosdisponibleanteriormente.HemosusadounasentenciamatchparadeterminarexactamentequetipodeOrderinges.Orderingesunenum,abreviacionparaenumeration,lascualeslucendelasiguientemanera:

    enumFoo{Bar,Baz,}

    Conestadefinicin,cualquiercosadetipoFoopuedeserbienseaunFoo::BarounFoo::Baz.Usamosel::paraindicarelespaciodenombresparaunavarianteenumenparticular.

    LaenumOrderingtienetresposiblesvariantes:Less,Equal,andGreater(menor,igualymayorrespectivamente).La

    Comparandoadivinanzas

    ElLenguajedeProgramacionRust

    25JuegodeAdivinanzas

  • sentenciamatchtomaunvalordeuntipo,ytepermitecrearunbrazoparacadavalorposible.DebidoaquetenemostresposiblestiposdeOrdering,tenemostresbrazos:

    matchguess.cmp(&secret_number){Ordering::Less=>println!("Muypequeo!"),Ordering::Greater=>println!("Muygrande!"),Ordering::Equal=>println!("Hazganado!"),}

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

    Anteriormentemencionequetodavianofunciona.Pongamosloaprueba:

    $cargobuildCompilingadivinanzasv0.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:abortingduetopreviouserrorCouldnotcompile`adivinanzas`.

    Oops!Ungranerror.Loprincipalenelesquetenemostiposincompatibles(mismatchedtypes).Rustposeeunfuerte,sistemadetiposestatico.Sinembargo,tambintieneinferenciadetipos.Cuandoescribimosletcorazonada=String::new(),RustfuecapazdeinferirquecorazonadadebiaserunString,yporellononoshizoescribireltipo.Connuestronumero_secreto,hayunnumerodetiposquepuedentenerunvalorentreunoycien:i32,unnumerodetreintaydosbits,u32,unnumerosinsignodetreintaydosbits,oi64unnumerodesesentaycuatrobitsuotros.Hastaahora,esonohaimportado,debidoaqueRustpordefectousai32.Sinembargo,enestecaso,Rustnosabecomocompararcorazonadaconnumero_secreto.Ambosnecesitanserdelmismotipo.Alafinal,queremosconvertirelStringqueleimoscomoentradaenuntiporealdenumero,paraefectosdelacomparacin.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){

    ElLenguajedeProgramacionRust

    26JuegodeAdivinanzas

  • Ordering::Less=>println!("Muypequeo!"),Ordering::Greater=>println!("Muygrande!"),Ordering::Equal=>println!("Hazganado!"),}}

    Lastresnuevaslineas:

    letcorazonada:u32=corazonada.trim().parse().ok().expect("Porfavorintroduceunnumero!");

    Esperaunmomento,pensqueyateniamosunacorazonada?Latenemos,peroRustnospermitesobreescribir(shadow)lacorazonadapreviaconunanueva.Estoesusadoconfrecuenciaenestamismasituacin,endondecorazonadaesunString,peroqueremosconvertirloaunu32.Esteshadowingnospermitereusarelnombrecorazonadaenvezdeforzarnosaideardosnombresnicoscomocorazonada_strycorazonada,uotros.

    Estamosasociandocorazonadaaunaexpresinquelucecomoalgoqueescribimosanteriormente:

    guess.trim().parse()

    Seguidoporunainvocacinaok().expect().Aqucorazonadahacereferenciaalaviejaversin,laqueeraunStringquecontenanuestraentradadeusuarioenella.Elmetodotrim()enlosStringseliminacualquierespacioenblancoalprincipioyalfinaldenuestrascadenasdecaracteres.Estoesimportante,debidoaquetuvimosquepresionarlateclaretornoparasatisfaceraread_line().Estosignificaquesiescribimos5ypresionamosretornocorazonadalucecomoas:5\n.El\nrepresentanuevalinea(newline),lateclaenter.trim()sedeshacedeesto,dejandonuestracadenadecaracteressoloconel5.Elmetodoparse()enlascadenascaracteresparseaunacadenadecaracteresenalgntipodenumero.Debidoaquepuedeparsearunavariedaddenumeros,debemosdarleaRustunapistadeltipoexactodenumeroquedeseamos.Deahlaparteletcorazonada:u32.Losdospuntos(:)despuesdecorazonadaledicenaRustquevamosaanotareltipo.u32esunenterosinsignodetreintaydosbits.Rustposeeunavariedaddetiposnumerointegrados,peronosotroshemosescojidou32.Esunabuenaopcinpordefectoparaunnumeropositivopequeo.

    Aligualqueread_line(),nuestrallamadaaparse()podriacausarunerror.QuetalsinuestracadenadecaracterescontieneA?Nohabraformadeconvertiresoenunnumero.Esporelloqueharemoslomismoquehicimosconread_line():usarlosmetodosok()yexpect()paraterminarabruptamentesihayalgunerror.

    Probemosnuestroprograma!

    $cargorunCompilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)Running`target/adivinanzas`Adivinaelnumero!Elnumerosecretoes:58Porfavorintroducetucorazonada.76Tucorazonadafue:76Muygrande!

    Excelente!Puedesverqueinclusoheagregadoespaciosantesdemiintento,yaunaselprogramadeterminoqueintente76.Ejecutaelprogramaunaspocasveces,yverificaqueadivinarelnumerofunciona,asicomointentarunnumeromuypequeno.

    Ahoratenemoslamayoriadeljuegofuncionando,perosolopodemosintentaradivinarunavez.Tratemosdecambiaresoagregandociclos!

    ElLenguajedeProgramacionRust

    27JuegodeAdivinanzas

  • Lapalabraclaveloopnosproporcionauncicloinfinito.Agreguemosla:

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

    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!("Muypequeo!"),Ordering::Greater=>println!("Muygrande!"),Ordering::Equal=>println!("Hazganado!"),}}}

    Pruebalo.Peroespera,noacabamosdeagregaruncicloinfinito?Sip.Recuerdasnuestradiscusinacercadeparse()?Sidamosunarespuestanonumrica,retornaremos(return)yfinalizaremoslaejecucin.Observa:

    $cargorunCompilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)Running`target/adivinanzas`Adivinaelnumero!Elnumerosecretoes:59Porfavorintroducetucorazonada.45Tucorazonadafue:45Muypequeo!Porfavorintroducetucorazonada.60Tucorazonadafue:60Muygrande!Porfavorintroducetucorazonada.59Tucorazonadafue:59Hazganado!Porfavorintroducetucorazonada.quitthread''panickedat'Pleasetypeanumber!'

    Ja!quitenefectoterminalaejecucin.Asicomocualquierotraentradaquenoseaunnumero.Bueno,estoes

    Iteracin

    ElLenguajedeProgramacionRust

    28JuegodeAdivinanzas

  • suboptimopordecirlomenos.Primerosalgamoscuandoganemos:

    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!("Muypequeo!"),Ordering::Greater=>println!("Muygrande!"),Ordering::Equal=>{println!("Hazganado!");break;}}}}

    Alagregarlalineabreakdespuesdel"Hazganado!",romperemoselciclocuandoganemos.Salirdelciclotambinsignificasalirdelprograma,debidoaqueeslaultimacosaenmain().Solonosquedaunasolamejoraporhacer:cuandoalguienintroduzcaunvalornonumrico,noqueremosterminarlaejecucin,queremossimplementeignorarlo.Podemoshacerlodelasiguientemanera:

    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,

    ElLenguajedeProgramacionRust

    29JuegodeAdivinanzas

  • };

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

    matchcorazonada.cmp(&numero_secreto){Ordering::Less=>println!("Muypequeo!"),Ordering::Greater=>println!("Muygrande!"),Ordering::Equal=>{println!("Hazganado!");break;}}}}

    Estassonlaslineasquehancambiado:

    letcorazonada:u32=matchcorazonada.trim().parse(){Ok(num)=>num,Err(_)=>continue,};

    Esasicomopasamosdeterminarabruptamenteenunerroraefectivamentemanejarelerror,atravsdelcambiodeok().expect()aunasentenciamatch.ElResultretornadoporparse()esunenumjustocomoOrdering,peroenestecasocadavariantetienedataasociada:Okesexito,yErresunafalla.Cadaunocontienemasinformacin:elenteroparseadoenelcasoexitoso,ountipodeerror.EnestecasohacemosmatchenOk(num),elcualasignaelvalorinternodelOkaelnombrenum,yseguidamenteretornaenelladoderecho.EnelcasodeErr,nonosimportaquetipodeerrores,esporelloqueusamos_enlugardeunnombre.Estoignoraelerrorycontinuenosmuevealasiguienteiteracindelciclo(loop).

    Ahoradeberiamosestarbien!Probemos:

    $cargorunCompilingadivinanzasv0.1.0(file:///home/tu/proyectos/adivinanzas)Running`target/adivinanzas`Adivinaelnumero!Elnumerosecretoes:61Porfavorintroducetucorazonada.10Tucorazonadafue:10Muypequeo!Porfavorintroducetucorazonada.99Tucorazonadafue:99Muypequeo!Porfavorintroducetucorazonada.fooPorfavorintroducetucorazonada.61Tucorazonadafue:61Hazganado!

    Genial!Conunaultimamejora,finalizamoseljuegodelasadvinanzas.Teimaginascuales?Escorrecto,noqueremosimprimirelnumerosecreto.Erabuenoparalaspruebas,peroarruinanuestrojuego.Heaquinuestrocdigofuentefinal:

    externcraterand;

    usestd::io;usestd::cmp::Ordering;userand::Rng;

    fnmain(){println!("Adivinaelnumero!");

    ElLenguajedeProgramacionRust

    30JuegodeAdivinanzas

  • 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!("Muypequeo!"),Ordering::Greater=>println!("Muygrande!"),Ordering::Equal=>{println!("Hazganado!");break;}}}}

    Enestepunto,hasterminadosatisfactoriamenteeljuegodelasadivinanza!Felicitaciones!

    Esteprimerproyectoteensenounmontn:let,match,metodos,funcionesasociadas,usarcratesexternos,ymas.Nuestrosiguienteproyectodemostraraaunmas.

    Completado!

    ElLenguajedeProgramacionRust

    31JuegodeAdivinanzas

  • Paranuestrosegundoproyecto,echemosunvistazoaunproblemaclsicodeconcurrencia.SellamaLacenadelosfilsofos.FueoriginalmenteconcebidoporDijkstraen1965,peronosotrosusaremosunaversionligeramenteadaptadadeestepaperporTonyHoareen1985.

    Entiemposancestrales,unfilntropoadineradopreparounauniversidadparaalojaracincofilsofoseminentes.Cadafilsofoteniaunahabitacinenlacualpodadesempearsuactividadprofesionaldelpensamiento:tambinhabauncomedorencomn,amobladoconunamesacircular,rodeadaporcincosillas,cadaunaidentificadaconelnombredelfilosofoquesesentabaenella.Losfilsofossesentabanensentidoanti-horarioalrededordelamesa.Alaizquierdadecadafilsofoyacauntenedordorado,yenelcentrountazndeespagueti,elcualeraconstantementerellenado.Seesperabaqueunfilsofoemplearalamayoradesutiempopensando;perocuandosesintieranconhambre,sedirigieraaelcomedortomaraeltenedorqueestabaasuizquierdaylosumieranenelespagueti.Perotaleranaturalezaenredadadelespaguetiqueunsegundotenedorerarequeridoparallevarloalaboca.Elfilsofoporendeteniaquetambintomareltenedorasuderecha.Cuandoterminabandebanbajarambostenedores,levantarsedelasillaycontinuarpensando.Porsupuesto,untenedorpuedeserusadoporunsolofilsofoalavez.Siotrofilsofolodesea,tienequeesperarhastaqueeltenedorestedisponiblenuevamente.

    Esteproblemaclsicoexhibealgunoselementosdelaconcurrencia.Larazndeelloesqueesunasolucinefectivamentedifcildeimplementar:unaimplementacinsimplepuedegenerarundeadlock.Porejemplo,consideremosunalgoritmosimplequepodraresolveresteproblema:

    1. Unfilsofotomaeltenedorasuizquierda.2. Despustomaeltenedorenasuderecha.3. Come.4. Bajalostenedores.

    Ahora,imaginemosestasecuenciadeeventos:

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

    Existendiferentesformasderesolveresteproblema.Teguiaremosatravsdelasolucindeestetutorial.Porahora,comencemosmodelandoelproblema.Empecemosconlosfilsofos:

    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");

    LaCenadelosFilsofos

    ElLenguajedeProgramacionRust

    32LaCenadelosFilsofos

  • }Ac,creamosunaestructura(struct)pararepresentarunfilsofo.Porahoraelnombreestodoloquenecesitamos.ElegimoseltipoStringparaelnombre,envezde&str.Generalmentehablando,trabajarcontipoqueesdueo(poseepertenencia)desudataesmasfcilquetrabajarconunoqueusereferencias.

    Continuemos:

    #structFilosofo{#nombre:String,#}implFilosofo{fnnew(nombre:&str)->Filosofo{Filosofo{nombre:nombre.to_string(),}}}

    EstebloqueimplnospermitedefinircosasenestructurasFilosofo.Enestecasoestamosdefiniendounafuncinasociadallamadanew.Laprimeralinealuceas:

    #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?Esmasfcildellamar.SirecibiramosunStringperoquiennosllamatuvieseun&strellosseveranenlaobligacindellamar.to_string()desulado.Ladesventajadeestaflexibilidadesquesiemprehacemosunacopia.Paraestepequeoprograma,estonoesparticularmenteimportante,yquesabemosqueestaremosusandocadenascortasdecualquiermodo.

    Unaultimacosasquehabrsnotado:solodefinimosunFilosofo,ynoparecemoshacernadaconel.Rustesunlenguajebasadoenexpresiones,loquesignificaquecasicualquiercosaenRustesunaexpresinqueretornaunvalor.Estoes

    ElLenguajedeProgramacionRust

    33LaCenadelosFilsofos

  • ciertoparalasfuncionestambin,laultimaexpresinesretornadaautomticamente.DebidoaquecreamosunnuevoFilosofocomolaultimaexpresindeestafuncin,terminamosretornndolo.

    Elnombrenew(),noesnadaespecialparaRust,peroesunaconvencinparafuncionesquecreannuevasinstanciasdeestructuras.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,creamoscincovariablesconcinconuevosfilsofos.Estossonmiscincofavoritos,peropuedessubstituirlosconquienesprefieras.Denohaberdefinidolafuncinnew(),main()luciraas:

    #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.Usarnewtienetambinposeeotrasventajas,peroinclusoenestesimplecasoterminaporserdemejorutilidad.

    Ahoraquetenemoslobsicoensulugar,hayunnumerodemanerasenlascualespodemosatacarelproblemamasamplio.Amimegustacomenzarporelfinal:creemosunaformaparaquecadafilosofopuedafinalizardecomer.Comounpasopequeo,hagamosunmtodo,yluegoiteremosatravsdetodoslosfilsofosllamndolo:

    structFilosofo{nombre:String,}

    implFilosofo{fnnew(nombre:&str)->Filosofo{Filosofo{nombre:nombre.to_string(),}}

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

    fnmain(){letfilosofos=vec![

    ElLenguajedeProgramacionRust

    34LaCenadelosFilsofos

  • Filosofo::new("JudithButler"),Filosofo::new("GillesDeleuze"),Filosofo::new("KarlMarx"),Filosofo::new("EmmaGoldman"),Filosofo::new("MichelFoucault"),];

    forfin&filosofos{f.comer();}}

    Primeroveamosamain().Enlugardetenercincovariablesindividualesparanuestrosfilsofos,creamosunVec.Vecesllamadotambinunvector,yesunarreglocapazdecrecer.Despususamosunciclo[for][for]paraiteraratravsdelvector,obteniendounreferenciaacadafilosofoalavez.

    Enelcuerpodelbucle,llamamosf.comer();,queestadefinidocomo:

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

    EnRust,losmtodosrecibenunparmetroexplcitoself.Esporelloquecomer()esunmtodoynewesunafuncinasociada:new()notieneself.Paranuestraprimeraversiondecomer(),soloimprimimoselnombredelfilsofo,ymencionamosquehafinalizadodecomer.Ejecutaresteprogramadebergenerarlasiguientesalida:

    JudithButlerhafinalizadodecomer.GillesDeleuzehafinalizadodecomer.KarlMarxhafinalizadodecomer.EmmaGoldmanhafinalizadodecomer.MichelFoucaulthafinalizadodecomer.

    Muyfcil,todoshanterminadodecomer!Peronohemosimplementadoelproblemarealtodava,asqueaunnoterminamos!

    Acontinuacin,nosoloqueremossolofinalicendecomer,sinoqueefectivamentecoman.Heaqulasiguienteversin:

    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"),

    ElLenguajedeProgramacionRust

    35LaCenadelosFilsofos

  • Filosofo::new("EmmaGoldman"),Filosofo::new("MichelFoucault"),];

    forfin&filosofos{f.comer();}}

    Solounospocoscambios.Analicmoslosparteporparte.

    usestd::thread;

    usehacedisponiblesnombresennuestrombito(scope).Comenzaremosausarelmodulothreaddelabibliotecaestndar,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!

    Parahaceranuestrosfilsofoscomerdemaneraconcurrente,necesitamoshacerunpequeocambio.

    Heaquilasiguienteiteracin:

    usestd::thread;

    structFilosofo{nombre:String,}

    implFilosofo{fnnew(nombre:&str)->Filosofo{Filosofo{nombre:nombre.to_string(),}}

    fncomer(&self){

    ElLenguajedeProgramacionRust

    36LaCenadelosFilsofos

  • 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();

    Aunassonsolocincolineas,soncincodensaslineas.Analicemosporpartes.

    lethandles:Vec=

    Introducimosunanuevavariable,llamadahandles.Lehemosdadoestenombreporquecrearemosalgunosnuevoshilos,queresultaranenalgunoshandles(agarradores,manillas)aesosdichoshilosloscualesnospermitirncontrolarsuoperacin.Necesitamosanotareltipoexplcitamente,debidoaalgoqueharemosreferenciamasadelante.El_esunmarcadordeposicinparauntipo.Estamosdiciendohandlesesunvectordealgo,perotu,Rust,puedesdeterminarqueesesealgo.

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

    Tomamosnuestralistadefilsofosyllamamosinto_iter()enella.Estocreauniteradorqueseaduea(tomapertenencia)decadafilosofo.Necesitamoshacerestoparapoderpasarlosfilsofosanuestroshilos.Luegotomamoseseiteradoryllamamosmapenel,mtodoquetomaunclosurecomoargumentoyllamadichoclosureencadaunodeloselementosalavez.

    thread::spawn(move||{f.comer();})

    Esaqudondelaconcurrenciaocurre.Lafuncinthread::spawntomaunclosurecomoargumentoyejecutaeseclosure

    ElLenguajedeProgramacionRust

    37LaCenadelosFilsofos

  • enunnuevohilo.Elclosurenecesitaunaanotacinextra,move,paraindicarqueelclosurevaaaduearsedelosvaloresqueestacapturando.Principalmente,lavariablefdelafuncinmap.

    Dentrodelhilo,todoloquehacemosesllamaracomer();enf.

    }).collect();

    Finalmente,tomamoselresultadodetodosesasllamadasamapyloscoleccionamos.collect()losconvertirenunacoleccindealgunatipo,queeselporqueanotamoseltipoderetorno:queremosunVec.Loselementossonlosvaloresretornadosdelasllamadasathread::spawn,quesonhandlesaesoshilos.Whew!

    forhinhandles{h.join().unwrap();}

    Alfinaldemain(),iteramosatravsdeloshandlesllamandojoin()enellos,locualbloquealaejecucinhastaqueelhilohayacompletadosuejecucin.Estoaseguraqueelhilocompletesuejecucinantesqueelprogramatermine.

    Siejecutasesteprograma,verasquelosfilsofoscomensinorden!Tenemosmulti-hilos!

    GillesDeleuzeestacomiendo.GillesDeleuzehafinalizadodecomer.EmmaGoldmanestacomiendo.EmmaGoldmanhafinalizadodecomer.MichelFoucaultestacomiendo.JudithButlerestacomiendo.JudithButlerhafinalizadodecomer.KarlMarxestacomiendo.KarlMarxhafinalizadodecomer.MichelFoucaulthafinalizadodecomer.

    Peroqueacercadelostenedoresnoloshemosmodeladodeltodotodava.

    Parahacerlo,creemosunnuevostruct:

    usestd::sync::Mutex;

    structMesa{tenedores:Vec,}

    EstaMesacontieneunvectordeMutexes.Unmutexesunaformadecontrolarconcurrencia,solounhilopuedeaccederelcontenidoalavez.Estaeslaexactamentelapropiedadquenecesitamosparanuestrostenedores.Usamosunaduplavaca,(),dentrodelmutex,debidoaquenovamosausarelvalor,solonosaferraremosael.

    ModifiquemoselprogramaparahacerusodeMesa:

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

    structFilosofo{nombre:String,izquierda:usize,derecha:usize,}

    implFilosofo{

    ElLenguajedeProgramacionRust

    38LaCenadelosFilsofos

  • fnnew(nombre:&str,izquierda:usize,derecha:usize)->Filosofo{Filosofo{nombre:nombre.to_string(),izquierda:izquierda,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,}

    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,conestaiteracin,hemosobtenidounprogramafuncional.Veamoslosdetalles:

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

    Usaremosotraestructuradelpaquetestd::sync:Arc.

    Hablaremosmasacercadeellacuandolausemos.

    structFilosofo{nombre:String,izquierda:usize,derecha:usize,}

    ElLenguajedeProgramacionRust

    39LaCenadelosFilsofos

  • VamosanecesitaragregardoscamposmasanuestraestructuraFilosofo.Cadafilosofotendrdostenedores:eldelaizquierda,yeldeladerecha.Usaremoseltipousizeparaindicarlos,debidoaqueesteeseltipoconelcualseindexanlosvectores.EstosdosvaloressernindicesenlostenedoresquenuestraMesaposee.

    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,tambinhemosagregadounargumento,mesa.AccedemosalalistadetenedoresdelaMesa,ydespususamosself.izquierdayself.derechaparaaccederaltenedorenunindiceenparticular.EsonosdaaccesoalMutexeneseindice,endondellamamoslock().Sielmutexestasiendoaccedidoactualmenteporalguienmas,nosbloquearemoshastaqueestedisponible.

    Lallamadaalock()puedefallar,ysilohace,queremosterminarabruptamente.Enestecasoelerrorquepuedeocurriresqueelmutexesteenvenenado(poisoned),queesloqueocurrecuandoelhilohacepnicomientraselmantieneelbloqueo.Debidoaqueestonodeberaocurrir,simplementeusamosunwrap().

    Otracosaextraaacercadeestalineas:hemosnombradolosresultados_izquierdaand_derecha.Quehayconesesub-guion?Bueno,enrealidadnoplaneamosusarelvalordentrodelbloqueo.Soloqueremosadquirirlo.Aconsecuencia,Rustnosadvertirquenuncausamoselvalor.Atravsdelusodelsub-guionledecimosaRustqueesloquequisimos,deesamaneranogeneraralaadvertencia.

    Queacercadesoltarelbloqueo?,Bueno,estoocurrircuando_izquierday_derechasalgandembito,automticamente.

    letmesa=Arc::new(Mesa{tenedores:vec![Mutex::new(()),Mutex::new(()),Mutex::new(()),Mutex::new(()),Mutex::new(()),]});

    Acontinuacin,enmain(),creamosunanuevaMesaylaenvolvemosenunArc.arcprovienedeatomicreferencecount(cuentadereferenciasatmica),necesitamoscompartirnuestraMesaentremultipleshilos.Amediaquelacompartimos,lacuentadereferenciassubir,ycuandocadahilotermine,irabajando.

    letfilosofos=vec![Filosofo::new("JudithButler",0,1),Filosofo::new("GillesDeleuze",1,2),

    ElLenguajedeProgramacionRust

    40LaCenadelosFilsofos

  • Filosofo::new("KarlMarx",2,3),Filosofo::new("EmmaGoldman",3,4),Filosofo::new("MichelFoucault",0,4),];

    NecesitamospasarnuestrosvaloresizquierdaandderechaalosconstructoresdenuestrosFilosofos.Perohayundetallemasaqu,yesmuyimportante.Siobservasalpatrn,esconsistentehastaelfinal,MonsieurFoucaultdebetener4,0comoargumentos,peroenvezdeestotiene0,4.Estoesloqueprevienedeadlocks,enefecto:unodelosfilsofoseszurdo!Esaesunaformaderesolverelproblema,yenmiopinion,eslamassimple.

    lethandles:Vec=filosofos.into_iter().map(|f|{letmesa=mesa.clone();

    thread::spawn(move||{f.comer(&mesa);})}).collect();

    Finalmente,dentrodenuestrociclomap()/collect(),llamamosmesa.clone().Elmtodoclone()enArcesloqueincrementalacuentadereferencias,ycuandosaledembito,ladecrementa.Notarasquepodemosintroducirunanuevavariablemesa,yestasobreescribir(shadow)laanterior.Estoesfrecuentementeusadodemanerataldenotenerqueinventardosnombresnicos.

    Contodoesto,nuestroprogramafunciona!Solodosfilosofopuedencomerenunmomentodadoyenconsecuenciatendrssalidaseveraas:

    GillesDeleuzeestacomiendo.EmmaGoldmanestacomiendo.EmmaGoldmanhafinalizadodecomer.GillesDeleuzehafinalizadodecomer.JudithButlerestacomiendo.KarlMarxestacomiendo.JudithButlerhafinalizadodecomer.MichelFoucaultestacomiendo.KarlMarxhafinalizadodecomer.MichelFoucaulthafinalizadodecomer.

    Felicitaciones!HazimplementadounproblemaclsicodeconcurrenciaenRust.

    ElLenguajedeProgramacionRust

    41LaCenadelosFilsofos

  • Paranuestrotercerproyecto,elegiremosalgoquedemuestraunadelasmayoresfortalezasdeRust:laausenciadeunentornodeejecucin.

    Amedidaquelasorganizacionescrecen,estasdemaneraprogresiva,hacenusodeunamultituddelenguajesdeprogramacin.Diferenteslenguajesdeprogramacinposeendiferentesfortalezasydebilidades,yunaarquitecturapoliglotapermiteusarunlenguajeenparticulardondesusfortalezashagansentidoyotrolenguajeseadbil.

    Unareamuycomnendondemuchoslenguajesdeprogramacinsondbileseselperformanceentiempodeejecucin.Frecuentemente,usarunlenguajequeeslento,peroofrecemayorproductividadparaelprogramador,esunequilibrioquevalelapena.Paraayudaramitigaresto,dichoslenguajesproveenunamaneradeescribirunapartedetusistemaenCyluegollamaresecdigocomosihubiesesidoescritoenunlenguajedemasaltonivel.Estafacilidadesdenominadainterfazdefuncionesforneas(foreignfunctioninterface),comnmenteabreviandoaFFI.

    RustposeesoporteparaFFIenambasdirecciones:puedellamarcdigoenCdemanerafcil,perocrucialmentepuedeserllamadotanfcilmentecomoC.Combinadoconlaausenciadeunrecolectordebasuraybajosrequerimientosentiempodeejecucin,RustesuncandidatoparaserembebidodentrodeotroslenguajescuandonecesitesesosooKmhextra.

    ExisteuncapitulocompletodedicadoaFFIysusdetallesenotrapartedellibro,peroenestecapitulo,examinaremoselusoparticulardeFFIconejemplosenRuby,Python,yJavaScript.

    Existenmuchosproblemasquepodramoshaberescogido,peroelegiremosunejemploenelcualRusttieneunaventajaclaraporencimadeotroslenguajes:computacinnumricaehilos.

    Muchoslenguajes,enhonoralaconsistencia,colocannmerosenelmontculo,envezdeenlapila.Especialmenteenlenguajesenfocadosenprogramacinorientadaaobjetosyelusodeunrecolectordebasura,laasignacindememoriadesdeelmontculoeselcomportamientopordefecto.Algunasvecesoptimizacionespuedencolocarciertosnmerosenlapila,peroenvezdeconfiarenunoptimizadorpararealizarestetrabajo,podramosquererasegurarnosquesiempreestemosusandonumeroprimitivosenvezdealguntipodeobjetos.

    Segundo,muchoslenguajesposeenunbloqueoglobaldelinterprete(globalinterpreterlock)(GIL),quelimitalaconcurrenciaenmuchassituaciones.Estoeshechoenelnombredelaseguridadlocualesunefectopositivo,perolimitalacantidaddetrabajoquepuedeserllevadoacabodemaneraconcurrente,locualesungrannegativo.

    Paraenfatizarestos2aspectos,crearemosunpequeoproyectoqueusaestosdosaspectosengranmedida.DebidoaqueelfocodelejemploesembeberRustenotroslenguajes,envezdeelproblemaensimismo,usaremosunejemplodejuguete:

    Iniciadiezhilos.Dentrodecadahilo,cuentadesdeunohastacincomillones.Despusquetodosloshiloshayanfinalizado,imprime"completado!".

    Heescogidocincomillonesbasadoenmicomputadorenparticular.HeaquunejemplodeestecdigoenRuby:

    threads=[]

    10.timesdothreads

  • 5_000_000.timesdocount+=1endendend

    threads.each{|t|t.join}puts"completado!"

    Intentaejecutaresteejemplo,yescogeunnumeroquecorraporunossegundos.Dependiendoenelhardwaredetucomputador,tendrsqueincrementarodecrementarelnumero.

    Enmisistema,ejecutaresteprogramatoma2.156.Siusoalgunatipodeherramientademonitoreodeprocesos,comotop,puedoverquesolousaunncleoenmimaquina.ElGILpresentehaciendosutrabajo.

    Sibienesciertoqueesteenunprogramasinttico,unopodraimaginarmuchosproblemassimilaresaesteenelmundoreal.Paranuestrospropsitos,levantarunospocoshilosyocuparlosrepresentaunaespeciedecomputacinparalelaycostosa.

    EscribamosesteproblemaenRust.Primero,creemosunproyectonuevoconCargo:

    $cargonewembeber$cdembeber

    EsteprogramaesfcildeescribirenRust:

    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_xencadaiteracin.Porqueelsub-guion?Bueno,siloremovemosyluegocompilamos:

    $cargobuildCompilingembeberv0.1.0(file:///Users/goyox86/Code/rust/embeber)src/lib.rs:3:1:16:2warning:functionisneverused:`procesar`,#[warn(dead_code)]onbydefaultsrc/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

    UnabibliotecaRust

    ElLenguajedeProgramacionRust

    43RustDentrodeOtrosLenguajes

  • src/lib.rs:6letmutx=0;^~~~~

    Laprimeraadvertenciaesdebidoesaconsecuenciadeestarconstruyendounabiblioteca.Situviramosunapruebaparaestafuncin,laadvertenciadesaparecera.Peroporahoranuncaesllamada.

    Lasegundaestarelacionadaaxversus_x.Comoproductodequeefectivamentenohacemosnadaconxobtenemosunaadvertencia.Eso,ennuestrocaso,estaperfectamentebien,puestoquequeremosdesperdiciarciclosdeCPU.Usandounsub-guindeprefijoeliminamoslaadvertencia.

    Finalmente,hacemosjoinencadaunodeloshilos.

    Hastaelmomento,sinembargo,esunabibliotecaRust,ynoexponenadaquepuedaserllamadodesdeC.Siquisiramosconectarlaconotrolenguaje,ensuestadoactual,nofuncionaria.Solonecesitamoshacerunospequeoscambiosparaarreglarlo.Loprimeroesmodificarelprincipiodenuestrocdigo:

    #[no_mangle]pubexternfnprocesar(){

    Debemosagregarunnuevoatributo,no_mangle.CuandocreamosunabibliotecaRust,estecambiaelnombredelafuncinenlasalidacompilada.Lasrazonesdeestoescapandelalcancedeestetutorial,peroparaqueotroslenguajespuedansabercomollamaralafuncin,debemosevitarqueelcompiladorcambieelnombreenlasalidacompilada.Esteatributodesactivaesecomportamiento.

    Elotrocambioeselpubextern.Elpubsignificaqueestafuncinpuedeserllamadadesdeafueradeestemodulo,yelexterndicequeestapuedeserllamadadesdeC.Esoestodo!Nomuchoscambios.

    LasegundacosaquenecesitamoshacerescambiarunaconfiguracinennuestroCargo.toml.Agregaestoalfinal:

    [lib]name="embeber"crate-type=["dylib"]

    EstaslineasleinformanaRustquequeremoscompilarnuestrabibliotecaenunabibliotecadinmicaestndar.Rustcompilaunrlib,unformatoespecificodeRust.

    Ahoraconstruyamoselproyecto:

    $cargobuild--releaseCompilingembeberv0.1.0(file:///Users/goyox86/Code/rust/embeber)

    Hemoselegidocargobuild--release,locualconstruyeelproyectoconoptimizaciones.Queremosquesealomasrpidoposible!Puedesencontrarlasalidadelabibliotecaentarget/release:

    $lstarget/release/builddepsexampleslibembeber.dylibnative

    Esalibembeber.dylibesnuestrabibliotecadeobjetoscompartidos.PodemosusarestabibliotecacomocualquierbibliotecadeobjetoscompartidoescritaenC!Comonota,estapodraserlibembeber.soolibembeber.dll,dependiendolaplataforma.

    ElLenguajedeProgramacionRust

    44RustDentrodeOtrosLenguajes

  • AhoraquetenemosnuestrabibliotecaRust,usmosladesdeRuby.

    Creaunarchivoembeber.rbdentrodenuestroproyecto,ycolocaestodentro:

    require'ffi'

    moduleHolaextendFFI::Libraryffi_lib'target/release/libembeber.dylib'attach_function:procesar,[],:voidend

    Hola.procesar

    puts'completado!'

    Antesdequepodamosejecutarlo,necesitamosinstalarlagemaffi:

    $geminstallffi#estopuedenecesitarsudoFetching:ffi-1.9.8.gem(100%)Buildingnativeextensions.Thiscouldtakeawhile...Successfullyinstalledffi-1.9.8Parsingdocumentationforffi-1.9.8Installingridocumentationforffi-1.9.8Doneinstallingdocumentationforffiafter0seconds1geminstalled

    Finalmente,intentemosejecutarlo:

    $rubyembeber.rbcompletado!$

    Whoa,esofuerpido!Enmisistema,tomo0.086segundos,adiferenciadelosdossegundosquelaversionenRubypuro.AnalicemosestecdigoRuby:

    require'ffi'

    Primeronecesitamosrequerirlagemaffi.NospermiteinteractuarconunabibliotecaRustcomounabibliotecaenC.

    moduleHolaextendFFI::Libraryffi_lib'target/release/libembeber.dylib'

    ElmoduloHolaesusadoparaadjuntarlasfuncionesnativasdelabibliotecacompartida.Dentro,extendemoselmoduloFFI::Libraryyluegollamamoselmtodoffi_libparacargarnuestrabibliotecadeobjetoscompartidos.Simplementepasamoslarutaenlacualnuestrabibliotecaestaalmacenada,lacual,comovimosanteriormente,estarget/release/libembeber.dylib.

    attach_function:procesar,[],:void

    Ruby

    ElLenguajedeProgramacionRust

    45RustDentrodeOtrosLenguajes

  • Elmtodoattach_functionesproporcionadoporlagemaFFI.Esloqueconectanuestrafuncinprocesar()enRustaunmtodoenRubyconelmismonombre.Debidoaqueprocesar()norecibeargumentos,elsegundoparmetroesunarreglovaco,yyaquenoretornanada,pasamos:voidcomoargumentofinal.

    Hola.procesar

    EstaeslallamadaaRust.Lacombinacindenuestromoduloylallamadaaattach_functionhanconfiguradotodo.SevecomounmtodoRubyperoesenrealidadcdigoRust!

    puts'completado!'

    Finalmente,ycomorequerimientodenuestroproyecto,imprimimoscompletado!.

    Esoestodo!Comohemosvisto,hacerunpuenteentrelosdoslenguajesesrealmentefcil,ynoscompramuchoperformance.

    Acontinuacin,probemosPython!

    Creaunarchivoembeber.pyenestedirectorio,ycolocaestoenel:

    fromctypesimportcdll

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

    lib.procesar()

    print("completado!")

    Aunmasfcil!Usamoscdlldelmoduloctypes.UnallamadarpidaaLoadLibrarydespus,yluegopodemosllamarprocesar().

    Enmisistema,toma0.017segundos.Rpidillo!

    Nodenoesunlenguaje,peroesactualmentelaimplementacindeJavascriptdominantedelladodelservidor.

    ParahacerFFIconNode,primeronecesitamosinstalarlabiblioteca:

    $npminstallffi

    Despusdequeesteinstalada,podemosusarla:

    varffi=require('ffi');

    varlib=ffi.Library('target/release/libembeber',{'procesar':['void',[]]});

    Python

    Node.js

    ElLenguajedeProgramacionRust

    46RustDentrodeOtrosLenguajes

  • lib.procesar();

    console.log("completado!");

    LucemasparecidoalejemploRubyquealdePython.Usamoselmoduloffiparaobteneraccesoaffi.Library(),lacualnospermitecargarnuestrabibliotecadeobjetoscompartidos.Necesitamosanotareltipoderetornoylostiposdelosargumentosdelafuncin,quesonvoidparaelretornoyunarreglovacopararepresentarningnargumento.Deallsimplementellamamosalafuncinprocesar()eimprimimoselresultado.

    Enmysistema,esteejemplotomaunosrpidos0.092segundos.

    Comopuedesver,lasbasesdehacerFFIsonmuyfciles.Porsupuestohaymuchomasquepodramoshaceraqu.EchaunvistazoalcapituloFFIparamasdetalles.

    Conclusion

    ElLenguajedeProgramacionRust

    47RustDentrodeOtrosLenguajes

  • Entonces,hazaprendidocomoescribiralgodecdigoRust.PerohayunadiferenciaentreescribircualquiercdigoRustyescribirbuencdigoRust.

    EstaseccinconsistedetutorialesrelativamenteindependientesquetemuestrancomollevartuRustalsiguientenivel.Patronescomunesycaractersticasdelabibliotecaestndarsernpresentados.Puedesleerdichasseccionesenelordenqueprefieras.

    RustEfectivo

    ElLenguajedeProgramacionRust

    48RustEfectivo

  • LaPilayelMonticulo

    ElLenguajedeProgramacionRust

    49LaPilayelMonticulo

  • Pruebas

    ElLenguajedeProgramacionRust

    50Pruebas

  • CompilacinCondicional

    ElLenguajedeProgramacionRust

    51CompilacinCondicional

  • Documentacin

    ElLenguajedeProgramacionRust

    52Documentacin

  • Iteradores

    ElLenguajedeProgramacionRust

    53Iteradores

  • Concurrencia

    ElLenguajedeProgramacionRust

    54Concurrencia

  • ManejodeErrores

    ElLenguajedeProgramacionRust

    55ManejodeErrores

  • FFI

    ElLenguajedeProgramacionRust

    56FFI

  • BorrowyAsRef

    ElLenguajedeProgramacionRust

    57BorrowyAsRef

  • CanalesdeDistribucin

    ElLenguajedeProgramacionRust

    58CanalesdeDistribucin

  • SintaxisySemntica

    ElLenguajedeProgramacionRust

    59SintaxisySemntica

  • Variables

    ElLenguajedeProgramacionRust

    60Variables

  • Funciones

    ElLenguajedeProgramacionRust

    61Funciones

  • TiposPrimitivos

    ElLenguajedeProgramacionRust

    62TiposPrimitivos

  • Comentarios

    ElLenguajedeProgramacionRust

    63Comentarios

  • if

    ElLenguajedeProgramacionRust

    64if

  • ciclosfor

    ElLenguajedeProgramacionRust

    65ciclosfor

  • cicloswhile

    ElLenguajedeProgramacionRust

    66cicloswhile

  • Pertenencia

    ElLenguajedeProgramacionRust

    67Pertenencia

  • ReferenciasyPrstamo

    ElLenguajedeProgramacionRust

    68ReferenciasyPrstamo

  • TiemposdeVida

    ElLenguajedeProgramacionRust

    69TiemposdeVida

  • Mutabilidad

    ElLenguajedeProgramacionRust

    70Mutabilidad

  • Estructuras

    ElLenguajedeProgramacionRust

    71Estructuras

  • Enumeraciones

    ElLenguajedeProgramacionRust

    72Enumeraciones

  • Match

    ElLenguajedeProgramacionRust

    73Match

  • Patrones

    ElLenguajedeProgramacionRust

    74Patrones

  • SintaxisdeMetodos

    ElLenguajedeProgramacionRust

    75SintaxisdeMetodos

  • Vectores

    ElLenguajedeProgramacionRust

    76Vectores

  • CadenasdeCaracteres

    ElLenguajedeProgramacionRust

    77CadenasdeCaracteres

  • Genricos

    ElLenguajedeProgramacionRust

    78Genricos

  • Rasgos

    ElLenguajedeProgramacionRust

    79Rasgos

  • Drop

    ElLenguajedeProgramacionRust

    80Drop

  • iflet

    ElLenguajedeProgramacionRust

    81iflet

  • ObjectosRasgo

    ElLenguajedeProgramacionRust

    82ObjectosRasgo

  • Closures

    ElLenguajedeProgramacionRust

    83Closures

  • SintaxisdeLlamadasaFuncionUniversal

    ElLenguajedeProgramacionRust

    84SintaxisdeLlamadasaFuncionUniversal

  • CajonesyModulos

    ElLenguajedeProgramacionRust

    85CajonesyModulos

  • constystatic

    ElLenguajedeProgramacionRust

    86`const`y`static`

  • Atributos

    ElLenguajedeProgramacionRust

    87Atributos

  • aliastype

    ElLenguajedeProgramacionRust

    88alias`type`

  • Conversinentretipos

    ElLenguajedeProgramacionRust

    89Conversinentretipos

  • TiposAsociados

    ElLenguajedeProgramacionRust

    90TiposAsociados

  • TipossinTamao

    ElLenguajedeProgramacionRust

    91TipossinTamao

  • OperadoresySobrecarga

    ElLenguajedeProgramacionRust

    92OperadoresySobrecarga

  • CoercionesDeref

    ElLenguajedeProgramacionRust

    93CoercionesDeref

  • %Macros

    Porahora,hasaprendidosobremuchaslasherramientasenRustparaabstraeryreutilizarelcdigo.Estasunidadesdereutilizacintienenunaricaestructurasemntica.Porejemplo,lasfuncionestienenuntipo,losparmetrosdetipotienenlmitesdetraits,yfunctionessobrecargadasdebenpertenecerauntraitparticular.

    Debidoaestaestructura,abstraccionesfundamentalesdeRusttienenpotentecomprobacindeexactitud.Pero,elprecioesflexibilidadreducida.Siseidentificavisualmenteunpatrndecdigorepetido,podraserdificilotediosoparaexpresaresepatrncomounafuncingenrica,untrait,ocualquierotrapartedelasemnticadeRust.

    Macrosnospermitenabstraeraunnivelsintctic.Unainvocacindemacroeslaabreviaturadeunaformasintctica"expandido".Estaexpansinocurredurantelacompilacin,antesdecomprobacinesttica.Comoresultado,lasmacrospuedencapturarmuchospatronesdereutilizacindecdigoquelasabstraccionesfundamentalesdeRustnopuede.

    Elinconvenienteesqueelcdigobasadoenlamacropuedesermsdifcildeentender,porquemenosdelasnormasincorporadasaplican.Aligualqueunafuncinordinaria,unamacrodebuencomportamientosepuedeutilizarsinentenderdetallesdeimplementacin.Sinembargo,puedeserdifcildisearunamacrodebuencomportamiento!Adems,loserroresdecompilacinencdigodemacrosonmsdifcilesdeentender,porquedescribenproblemasenelcdigoexpandido,noelformulariodeorigenquelosdesarrolladoresutilizan.

    Estosinconvenienteshacenmacrosuna"herramientadeltimorecurso".Esonoquieredecirquelasmacrossonmalos;sonpartedeRustporqueavecessenecesitanlasmacrosparacdigoconcisayabstrado.Slotengaencuentaesteequilibrio.

    Puedequehayavistolamacrovec!,utilizadoparainicializarunvectorconcualquiernmerodeelementos.

    letx:Vec=vec![1,2,3];#assert_eq!(&[1,2,3],&x);

    Estonopuedeserunafuncinordinaria,porqueaceptacualquiernmerodeargumentos.Peropodemosimaginarlocomoabreviaturasintcticapara

    letx:Vec={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.Lapropiadefinicindevec!enlibcollectionsdifieredela

    presentadaaqu,porrazonesdeeficienciayreutilizacin.

    macro_rules!vec{($($x:expr),*)=>{{letmuttemp_vec=Vec::new();

    Definicindeunamacro

    ElLenguajedeProgramacionRust

    94Macros

  • $(temp_vec.push($x);)*temp_vec}};}#fnmain(){#assert_eq!(vec![1,2,3],[1,2,3]);#}

    Whoa!,esoesmuchanuevasintaxis.Examinemospiezaporpieza.

    macro_rules!vec{...}

    Estedicequeestamosdefiniendounamacrollamadavec,tantocomofnvecdefiniraunafuncinllamadavec.Enprosa,informalmenteescribimoselnombredeunamacroconunsignodeexclamacin,porejemplo,vec!.Elsignodeexclamacinespartedelasintaxisdeinvocacinysirveparadistinguirunamacrodesdeunafuncinordinaria.

    Lamacrosedefineatravsdeunaseriedereglasdeemparejamientodepatrones.Porencima,tuvimos

    ($($x:expr),*)=>{...};

    Estoescomounbrazodeexpresinmatch,perocoincideconrbolesdesintaxisRustentiempodecompilacin.Elpuntoycomaesopcionalenelcasofinal(aqu,elnicocaso).El"patrn"enelladoizquierdode=>esconocidocomoun'matcher'.Estostienensupropiopequeogramticadentrodellanguage.

    Elmatcher$x:exprcoincidirconcualquierexpresinRust,vinculanteestarbolsintcticoala'metavariable'$x.Elidentificadorexpresun'especificadorfragmento';todaslasposibilidadesseenumeranmsadelanteenestecapitulo.Alrodearelmatchercon$(...),*,quecoincidirconceroomsexpresionesseparadasporcomas.

    Apartedelasintaxisespecialdematcher,lastokensRustqueaparecenenunmatcherdebencoincidirexactamente.Porejemplo,

    macro_rules!foo{(x=>$e:expr)=>(println!("modeX:{}",$e));(y=>$e:expr)=>(println!("modeY:{}",$e));}

    fnmain(){foo!(y=>3);}

    imprimir

    modeY:3

    Con

    foo!(z=>3);

    Emparejamientodepatrones

    ElLenguajedeProgramacionRust

    95Macros

  • obtenemoselerrordelcompilador

    error:norulesexpectedthetoken`z`

    ElladoderechodeunareglamacroeslasintaxisRustordinaria,ensumayorparte.Peropodemosinsertarpartesdesintaxiscapturadosporelmatcher.Delejemplooriginal:

    $(temp_vec.push($x);)*

    Cadaexpresinemparejado$xproducirunasolaexpresinpushenlaexpansindemacros.Larepeticinsedesar