el libro de rust (lenguaje de programación)
Post on 14-Jan-2016
131 Views
Preview:
DESCRIPTION
TRANSCRIPT
-
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
top related