Rust (linguaxe de programación)

Rust é unha linguaxe de programación de propósito xeral que resalta rendemento, seguridade de tipos e concorrencia. Aplica seguridade da memoria, o que significa que todas as referencias que apuntan a memoria válida. Faino sen un colector de lixo convencional; en vez diso, erros de seguridade da memoria e condicións de carreira en acceso a datos son evitados polo "borrow checker", que rastrexa a duración dos obxectos das referencias en tempo de compilación.

Rust soporta múltiples paradigmas de programación. Foi influído por ideas dende programación funcional, incluíndo inmutabilidade, funcións de orde superior, tipos de datos alxebraicos, e "pattern matching". Tamén soporta programación orientada a obxectos vía structs, enums, traits, e métodos.

O desenvolvedor de software Graydon Hoare creou Rust como proxecto persoal mentres traballaba en Mozilla Research en 2006. Mozilla oficialmente patrocinou o proxecto en 2009. A primeira liberación estábel de Rust, Rust 1.0, foi publicado en maio de 2015. Tras un despido masivo de persoal en Mozilla en agosto de 2020, varias empresas unironse a Mozilla para patrocinar Rust coa creación da Rust Fundation en febreiro de 2021. En decembro de 2022, Rust converteuse na primeira linguaxe ademais de C e ensamblador en ser soportada no desenvolvemento do Linux kernel.

Rust destacou pola súa adopción en moitos proxectos de software, especialmente en servizos web e software de sistema. Foi obxecto de estudo académico e conta cunha comunidade crecente de desenvolvedores.

 Historia 

 2006–2009: primeiros anos 
dereita|miniatura|Sede da Fundación Mozilla, 650 Castro Street, en Mountain View, California, xuño de 2009
Rust comezou como un proxecto persoal do empregado de Mozilla Graydon Hoare en 2006. Hoare iniciou o proxecto debido á súa frustración cun ascensor avariado no seu edificio de apartamentos. Hoare afirmou que Rust recibiu ese nome polo grupo de fungos de ferruxe que están "sobredeseñados para a supervivencia". Durante o período comprendido entre 2006 e 2009, Rust non se fixo público dentro de Mozilla e foi escrito no tempo libre de Hoare;   Hoare empezou falar publicamente da linguaxe cara a 2009, despois de que un pequeno grupo de Mozilla mostrase interese no proxecto. Hoare enfatizou a prioridade de aproveitar boas ideas de linguaxes antigas en lugar de desenvolver novas, citando linguaxes como CLU (1974), BETA (1975), Mesa (1977), NIL (1981), Erlang (1987), Newsqueak (1988), Napier (1988), Hermes (1990), Sather (1990), Alef (1992), e Limbo (1996) como influencias, afirmando que "moitas linguaxes vellas [son] mellores que as novas", e describindo Rust como "tecnoloxía do pasado que vén a salvar o futuro de si mesmo".  Un dos primeiros desenvolvedores de Rust, Manish Goregaokar, describiu de xeito similar que Rust se baseaba en “investigación principalmente de varias décadas atrás”.

Durante os anos temperáns, o compilador de Rust foi escrito en aproximadamente 38,000 liñas de OCaml.  A versión inicial de Rust incluía características como programación orientada a obxectos explícita mediante unha palabra clave obj

(máis tarde eliminada),  e un sistema de "tipos-estados" que permitía seguimento das variables dun tipo xunto cos cambios de estado (por exemplo, de non inicializada a inicializada).

 2009–2012: patrocinio de Mozilla 
Mozilla patrocinou oficialmente o proxecto Rust en 2009. Brendan Eich e outros directivos, intrigados pola posibilidade de empregar Rust para un motor de navegador de web seguro, asignaron enxeñeiros ao proxecto, incluíndo a Patrick Walton, Niko Matsakis, Felix Klock e Manish Goregaokar. Unha sala de conferencias ocupada polos desenvolvedores do proxecto foi bautizada como «the nerd cave», cun cartel colocado fóra da porta.

Durante este período, o traballo trasladouse do compilador inicial en OCaml a un compilador autorreferido, é dicir, escrito en Rust e baseado en LLVM. O sistema de propiedade de Rust tamén estaba en funcionamento cara a 2010. O logotipo de Rust desenvolveuse en 2011 inspirado nun anel dentado de cadea de bicicleta.

O primeiro lanzamento público, Rust 0.1, saíu o 20 de xaneiro de 2012 para Windows, Linux e macOS. A principios da década de 2010 incrementouse a participación de voluntarios de código aberto fóra de Mozilla e fóra dos Estados Unidos. En Mozilla, os directivos acabarían contratando a máis dunha ducia de enxeñeiros para traballar a tempo completo en Rust durante a seguinte década.

 2012–2015: Evolución 
Os anos de 2012 a 2015 estiveron marcados por cambios substanciais no sistema de tipos de Rust, en particular a eliminación do sistema de typestate, a consolidación doutros recursos da linguaxe e a supresión do colector de lixo.  A xestión de memoria mediante o sistema de propiedade consolidouse e ampliouse gradualmente para previr erros relacionados coa memoria. En 2013 a funcionalidade do colector de lixo empregábase moi raramente e foi eliminada polo equipo en favor do sistema de propiedade. Outros cambios durante este período incluíron a eliminación das funcións puras—que se declaraban cunha anotación explícita pure

—en marzo de 2013. Así mesmo, suprimiuse a sintaxe especializada para canles e varios tipos de punteiros co obxectivo de simplificar a linguaxe.

A expansión e consolidación de Rust estivo influenciada por desenvolvedores procedentes de C++ (por exemplo, o rendemento de baixo nivel das características), linguaxes de script (por exemplo, Cargo e a xestión de paquetes) e a programación funcional (por exemplo, o desenvolvemento de sistemas de tipos).

Graydon Hoare abandonou o proxecto Rust en 2013. Isto permitiu que evolucionase de xeito orgánico baixo unha estrutura de gobernanza máis federada, cun “equipo núcleo” inicial de seis persoas,  arredor de 30–40 desenvolvedores en diversos equipos,  e un proceso de Request for Comments (RFC) para novas características da linguaxe engadido en marzo de 2014.  O equipo núcleo medrou ata nove persoas en 2016 , con máis de 1600 RFCs propostos.

Segundo Andrew Binstock, escribindo para a revista Dr. Dobb’s Journal en xaneiro de 2014, aínda que Rust «era amplamente considerado como unha linguaxe extraordinariamente elegante», a súa adopción ralentizouse porque cambiaba radicalmente dunha versión a outra. Nese momento, o desenvolvemento de Rust centrárase en rematar as funcionalidades da linguaxe e avanzar cara á versión 1.0, de modo que se puidese comezar a garantir compatibilidade cara atrás.

Seis anos despois de que Mozilla patrocinase o seu desenvolvemento, a primeira versión estable, Rust 1.0, publicouse o 15 de maio de 2015. Un ano despois do lanzamento, o compilador de Rust acumulou máis de 1400 contribuíntes e había máis de 5000 bibliotecas de terceiros publicadas no sitio de xestión de paquetes de Rust, Crates.io.

 2015–2020: Servo e adopción inicial 
dereita|miniatura|Primeira páxina de inicio do  motor de navegación Servo de Mozilla
O desenvolvemento do motor de navegador Servo continuou en paralelo con Rust, financiado conxuntamente por Mozilla e Samsung. Os equipos detrás de ambos proxectos traballaron en estreita colaboración; as novas funcionalidades en Rust foron probadas polo equipo de Servo, e as novas funcionalidades en Servo empregábanse para proporcionar retroalimentación ao equipo de Rust.  A primeira versión de Servo lanzouse en 2016. O navegador Firefox incluíu código en Rust dende 2016 (versión 45), pero compoñentes de Servo non apareceron en Firefox ata setembro de 2017 (versión 57) como parte dos proxectos Gecko e Quantum.

Durante os anos posteriores á versión 1.0, mellorouse o ecosistema da cadea de ferramentas de Rust, incluíndo Rustfmt, a integración con contornos de desenvolvemento integrado; un ciclo regular de probas e publicacións do compilador; un código de conduta comunitario; e as discusións da comunidade organizadas mediante IRC.

As primeiras adopciones fóra de Mozilla foron realizadas por proxectos individuais en Samsung, Facebook (agora Meta Platforms), Dropbox e outros, incluíndo Tilde, Inc. (a empresa detrás de ember.js). Amazon Web Services uniuse en 2020. Os enxeñeiros argumentaron que escolleron Rust polas súas prestacións, pola ausencia dun colector de lixo, pola seguridade e pola agradable experiencia de desenvolvemento que ofrece a linguaxe, aínda que recoñecían que era unha aposta arriscada por tratarse dunha tecnoloxía nova. Os desenvolvedores de Amazon citaron un achado de investigadores portugueses que demostraba que o código Rust consome menos enerxía en comparación con código similar escrito en Java e C++, só superado por C.

 2020–presente: despidos en Mozilla e Fundación Rust 
En agosto de 2020, Mozilla despediu a 250 dos seus 1 000 empregados en todo o mundo como parte dunha reestruturación corporativa provocada pola pandemia de COVID-19. O equipo detrás de Servo foi desmantelado. Este acontecemento xerou preocupacións sobre o futuro de Rust debido á superposición entre ambos proxectos. Na semana seguinte, o Rust Core Team recoñeceu o grave impacto destes despedimentos e anunciou que se estaban a elaborar plans para crear unha fundación Rust. O primeiro obxectivo da fundación sería facerse cargo de todas as marcas rexistradas e nomes de dominio, así como asumir a responsabilidade financeira dos seus custos.

O 8 de febreiro de 2021 anunciouse a formación da Rust Foundation polos cinco patrocinadores fundadores: Amazon Web Services, Google, Huawei, Microsoft e Mozilla. A fundación, dirixida por Shane Miller durante os seus primeiros dous anos, ofreceu subvencións de 20.000$ e outro apoio para programadores que traballasen en funcións principais de Rust. Nunha entrada no blog publicada o 6 de abril de 2021, Google anunciou o soporte de Rust no proxecto de código aberto de Android como alternativa a C/C++.

O 22 de novembro de 2021, o Equipo de Moderación, responsable de facer cumprir o código de conduta da comunidade, anunciou a súa renuncia “en protesta de que o Equipo Núcleo se poñese sen rendición de contas ante ninguén máis que ante eles mesmos”. En maio de 2022, o Equipo Núcleo de Rust, outros programadores líderes e certos membros da xunta da Rust Foundation implementaron reformas de gobernanza en resposta a este incidente.

A Rust Foundation publicou o 6 de abril de 2023 un borrador dunha nova política de marcas rexistradas, que incluía regras sobre como se pode empregar o logotipo e o nome de Rust, o que provocou reaccións negativas por parte de usuarios e colaboradores de Rust.

O 26 de febreiro de 2024, a Casa Branca dos Estados Unidos, a través da Oficina do Director Nacional de Ciberseguridade, publicou un informe de prensa de 19 páxinas instando ao desenvolvemento de software a afastarse de C e C++ e fomentando o uso de linguaxes seguras para a memoria como C#, Go, Java, Ruby, Swift e Rust. O informe foi interpretado como un impulso ao interese por Rust.

 Sintaxe e características 

A sintaxe de Rust é semellante á de C e C++; aínda que moitas das súas características foron influenciadas por linguaxes de programación funcional como OCaml. Hoare describiu Rust como dirixido a programadores frustrados de C++ e enfatizou características como a seguridade, o control do deseño da memoria e a concorrencia. A seguridade en Rust inclúe as garantías de seguridade de memoria, seguridade de tipos e a ausencia de condicións de carreira de datos.

 Programa Ola Mundo 
Embaixo tes un programa “Ola mundo” en Rust. A palabra clave fn indica unha función, e a macro println! imprime a mensaxe na saída estándar. As instrucións en Rust sepáranse por punto e coma.fn main() {
    println!("Ola, Mundo!");
}

 Variables 
As variables en Rust defínense mediante a palabra clave let. O seguinte exemplo asigna un valor á variable chamada foo e amosa o seu valor.fn main() {
    let foo = 10;
    println!("O valor de foo é {foo}");
}As variables son inmutables por defecto, pero engadir a palabra clave mut permite mutar a variable. O seguinte exemplo usa //, que denota o inicio dun comentario.fn main() {
    // Este código non compilaría sen engadir "mut".
    let mut foo = 10; 
    println!("O valor de foo é {foo}");
    foo = 20;
    println!("O valor de foo é {foo}");
}Varias expresións let poden definir múltiples variables co mesmo nome, fenómeno coñecido como sombreado de variables. O sombreado de variables permite transformar valores sen ter que empregar nomes distintos para as variables. No exemplo seguinte declárase unha nova variable co mesmo nome que ten o dobre do valor orixinal:fn main() {
    let foo = 10;
    // Isto imprimirá "O valor de foo é 10"
    println!("O valor de foo é {foo}");
    let foo = foo * 2;
    // Isto imprimirá "O valor de foo é 20"
    println!("O valor de foo é {foo}");
}

O sombreado de variables tamén é posible con valores de tipos diferentes. Por exemplo, pasar dunha cadea de caracteres á súa lonxitude:fn main() {
    let letras = "abc";
    let letras = letras.len();
}

 Expresións de bloque e fluxo de control 
Unha expresión de bloque delimítase con chaves {}. Cando a última expresión dentro dun bloque non remata con punto e coma, o bloque evalúase co valor desa expresión final:fn main() {
    let x = {
        println!("isto está dentro do bloque");
        1 + 2
    };
    println!("1 + 2 = {x}");
}As expresións finais dos corpos de función utilízanse como valor de retorno:fn engadir_dous(x: i32) -> i32 {
    x + 2
}

 expresións if 
Unha expresión condicional if executa código en función de se o valor dado é verdadeiro. else úsase cando o valor evalúase a falso, e else if permite combinar múltiples condicións.fn main() {
    let x = 10;
    if x > 5 {
        println!("o valor é maior que cinco");
    }

    if x % 7 == 0 {
        println!("o valor é divisible por 7");
    } else if x % 5 == 0 {
        println!("o valor é divisible por 5");
    } else {
        println!("o valor non é divisible por 7 nin por 5");
    }
}Os bloques if e else poden avaliarse nun valor, que despois se pode asignar a unha variable:fn main() {
    let x = 10;
    let novo_x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };
    println!("{novo_x}");
}

 bucles while 
O while pódese usar para repetir un bloque de código mentres se cumpra unha condición.
 fn main() {
    // Itera sobre todos os enteiros de 4 a 10
    let mut valor = 4;
    while valor <= 10 {
         println!("valor = {valor}");
         valor += 1;
    }
}

 Os bucles e iteradores for 
Os bucles for en Rust percorren os elementos dunha colección. As expresións for funcionan con calquera tipo de iterador.fn main() {
    let r;                    // ------------------+- Tempo de vida 'a
                              //                   |
    {                         //                   |
        let x = 5;            // -+-- Tempo de vida 'b  |
        r = &x; // ERRO: x non vive o tempo suficiente
    }           //                             |
                //                             |
    println!("r: {}", r);     //                   |
}                             // ------------------+fn main() {
    // Usando `for` con sintaxe de rango para a mesma funcionalidade ca enriba
    // A sintaxe 4..=10 significa o rango de 4 a 10, incluíndo o 10.
    for valor in 4..=10 {
        println!("valor = {valor}");
    }
}No código anterior, 4..=10 é un valor do tipo Range que implementa o trait Iterator. O código dentro das chaves aplícase a cada elemento que devolve o iterador.

Os iteradores pódense combinar con funcións sobre iteradores como map, filter e sum. Por exemplo, o seguinte suma todos os números entre 1 e 100 que son múltiplos de 3:(1..=100).filter(|&x| x % 3 == 0).sum()

 As instrucións loop e break 
En xeral, a palabra clave loop permite repetir unha parte do código ata que se produza un break. 

break pode, opcionalmente, saír do bucle devolvendo un valor. No caso de bucles anidados, pódense empregar etiquetas denominadas 'nome_etiqueta para romper un bucle exterior en lugar do máis interno.fn main() {
    let valor = 456;
    let mut potencia = 1;
    let resultado = loop {
        potencia *= 10;
        if potencia > valor {
            break potencia / 10;
        }
    };
    println!("A maior potencia de dez que é menor ou igual a valor: {resultado}");

    let mut arriba = 1;
    'exterior: loop {
        let mut abaixo = 120;
        loop {
            if arriba > 100 {
                break 'exterior;
            }

            if abaixo < 4 {
                break;
            }

            abaixo /= 2;
            arriba += 1;
            println!("arriba: {arriba}, abaixo: {abaixo}");
        }
        arriba *= 2;
    }
}

 Coincidencia de patróns Pattern matching 
As expresións match e if let poden empregarse para a coincidencia de patróns. Por exemplo, match pode usarse para duplicar un valor enteiro opcional se está presente, e devolver cero en caso contrario:fn dobre(x: Option<u64>) -> u64 {
    match x {
        Some(y) => y * 2,
        None => 0,
    }
}Equivalentemente, isto pódese escribir con if let e else:trait Zero: Sized {
    fn zero() -> Self;
    fn is_zero(&self) -> bool
    where
        Self: PartialEq,
    {
        self == &Zero::zero()
    }
}

impl Zero for u32 {
    fn zero() -> u32 { 0 }
}

impl Zero for f32 {
    fn zero() -> Self { 0.0 }
}fn dobre(x: Option<u64>) -> u64 {
    if let Some(y) = x {
        y * 2
    } else {
        0
    }
}

 Tipos 
Rust é fortemente tipado e estáticamente tipado, o que significa que os tipos de todas as variables deben ser coñecidos en tempo de compilación. Asignar un valor dun tipo particular a unha variable dun tipo distinto provoca un erro de compilación. A inferencia de tipos emprégase para determinar o tipo das variables se non se especifica.

O tipo enteiro por defecto é i32, e o tipo de punto flotante por defecto é f64. Se o tipo dun literal numérico non se proporciona explicitamente, infírese do contexto ou utilízase o tipo por defecto.

 Tipos primitivos 
Os tipos enteiros en Rust chámanse en función da sinalidade e do número de bits que ocupa o tipo. Por exemplo, i32 é un enteiro con sinal que ocupa 32 bits de almacenamento, mentres que u8 é sen sinal e só ocupa 8 bits de almacenamento. isize e usize ocupan espazo segundo a arquitectura do ordenador que executa o código; por exemplo, en computadores con arquitecturas de 32 bits, ambos os tipos ocuparán 32 bits.

Por defecto, os literais enteiros están en base 10, pero están soportadas diferentes bases mediante prefixos; por exemplo, 0b11 para números binarios, 0o567 para octais e 0xDB para hexadecimais. Por defecto, os literais enteiros toman i32 como tipo. Pódense usar sufixos como 4u32 para establecer explicitamente o tipo dun literal. Literais de bytes como b'X' están dispoñibles para representar o valor ASCII (como un u8) dun carácter concreto.

O tipo booleano denomínase bool e pode tomar os valores true ou false. Un char ocupa 32 bits de espazo e representa un valor escalar Unicode: un punto de código Unicode que non é un surrogate. Os números en punto flotante segundo o estándar IEEE 754 son compatibles, con f32 para precisión simple e f64 para precisión dobre.

 Tipos compostos 
Os tipos compostos poden conter varios valores. As tuplas son listas de tamaño fixo que poden conter valores de tipos distintos. Os arrays (arranxos) son listas de tamaño fixo cuxos valores son do mesmo tipo. As expresións dos tipos tupla e array poden escribirse listando os valores, e pódense acceder mediante .index ou [index].let tupla: (u32, bool) = (3, true);
let array: [i8; 5] = [1, 2, 3, 4, 5];
let valor = tupla.1; // true
let valor = array[2]; // 3Os arrays tamén poden construírse copiando un único valor un número de veces
 let array2: [char; 10] = [' '; 10]; 

 Propiedade e referencias 
O sistema de propiedade de Rust consiste nun conxunto de regras que garanten a seguridade da memoria sen empregar un colector de lixo. En tempo de compilación, cada valor debe estar ligado a unha variable chamada propietario dese valor, e cada valor debe ter exactamente un propietario. Os valores móvense entre propietarios distintos mediante asignación ou pasando un valor como parámetro dunha función. Os valores tamén poden ser prestados, é dicir, pásanse temporalmente a outra función antes de ser devoltos ao propietario. Con estas regras, Rust pode evitar a creación e o uso de punteiros colgantes.
 fn print_string(s: String) {
    println!("{}", s);
}

fn main() {
    let s = String::from("Hello, World");
    print_string(s); // s consumido por print_string
    // s foi movida, polo que xa non se pode usar
    // outro print_string(s); produciría un erro de compilación
}A función print_string toma a propiedade do valor String que se lle pasa; como alternativa, & pode empregarse para indicar un tipo referencia (en &String) e para crear unha referencia (en &s).
 fn print_string(s: &String) {
    println!("{}", s);
}

fn main() {
    let s = String::from("Hello, World");
    print_string(&s); // s prestado por print_string
    print_string(&s); // s non foi consumida; podemos chamar a función varias veces
}

Debido a estas regras de propiedade, os tipos en Rust chámanse lineares ou afíns, o que significa que cada valor pode utilizarse exactamente unha vez. Isto impón unha forma de illamento de erros do software, xa que o propietario dun valor é o único responsable da súa corrección e da súa liberación.

Cando un valor sae do seu alcance, libérase executando o seu destructor. O destructor pódese definir programaticamente implementando o trait Drop. Isto axuda a xestionar recursos como manexos de ficheiros, sockets de rede e bloqueos, xa que cando os obxectos se eliminan, os recursos asociados péchanse ou libéranse automaticamente.

 Lifetimes 
O tempo de vida dun obxecto refírese ao período durante o cal unha referencia é válida; é dicir, o intervalo entre a creación e a destrución do obxecto. Estes tempos de vida (os chamados lifetimes) asócianse de forma implícita a todos os tipos de referencia en Rust. Aínda que o compilador moitos veces os infire, tamén poden indicarse de forma explícita mediante parámetros de lifetime nomeados (habitualmente denotados 'a, 'b, etc.).

Os tempos de vida (lifetimes) en Rust poden entenderse como lexicamente acoutados, o que significa que a duración do tempo de vida dun obxecto infírese a partir do conxunto de localizacións no código fonte (é dicir, función, número de liña e columna) nas que unha variable é válida. Por exemplo, unha referencia a unha variable local ten un tempo de vida correspondente ao bloque no que está definida.
 fn main() {
    let x = 5;                // ------------------+- Vida 'a
                              //                   |
    let r = &x;               // -+-- Vida 'b      |
                              //  |                |
    println!("r: {}", r);     //  |                |
                              //  |                |
                              // -+                |
}                             // ------------------+O borrow checker do compilador de Rust impón que as referencias só se utilicen nas localizacións do código fonte nas que o tempo de vida asociado sexa válido. No exemplo anterior, almacenar unha referencia á variable x en r é válido, porque x ten un tempo de vida máis longo ('a) que r ('b). Con todo, cando x ten un tempo de vida máis curto, o borrow checker rexeitaría o programa.
 fn main() {
    let r;                    // ------------------+- Vida 'a
                              //                   |
    {                         //                   |
        let x = 5;            // -+-- Vida 'b      |
        r = &x; // ERRO: x non vive o suficiente   |
    }           //                              ---|
                // non vive o tempo necesario      |
    println!("r: {}", r);     //                   |
}                             // ------------------+Dado que o tempo de vida da variable referenciada ('b) é máis curto ca o tempo de vida da variable que garda a referencia ('a), o borrow checker produce un erro, evitando que x se use fóra do seu ámbito.
Os tempos de vida (lifetimes) pódense indicar usando parámetros de tempo de vida explícitos nos argumentos dunha función. Por exemplo, o seguinte código especifica que a referencia devolta pola función ten o mesmo tempo de vida que original (e non necesariamente o mesmo tempo de vida que prefix):fn eliminar_prefixo<'a>(mut original: &'a str, prefix: &str) -> &'a str {
    if original.starts_with(prefix) {
        original = &original[prefix.len()..];
    }
    original
}No compilador, a propiedade e os tempos de vida traballan xuntos para previr problemas de seguridade da memoria, como os dangling pointers (punteros colgantes).

 Tipos definidos polo usuario 
Os tipos definidos polo usuario créanse coas palabras clave struct ou enum. A palabra clave struct úsase para indicar un tipo rexistro que agrupa varios valores relacionados. Os enum poden adoptar diferentes variantes en tempo de execución, con capacidades similares aos tipos de datos alxebraicos que se atopan en linguaxes de programación funcionais. Tanto os rexistros como as variantes de enum poden conter campos con diferentes tipos. Pódense definir nomes alternativos, ou alias, para o mesmo tipo coa palabra clave type.

A palabra clave impl pode definir métodos para un tipo definido polo usuario. Os datos e as funcións defínense por separado. As implementacións cumpren un papel similar ao das clases noutros linguaxes.

 Biblioteca estándar 
A biblioteca estándar de Rust define e implementa moitos tipos de datos personalizados amplamente usados, incluíndo estruturas de datos principais como Vec, Option e HashMap, así como tipos de punteiros intelixentes.

Rust tamén fornece un xeito de excluír a maior parte da biblioteca estándar empregando o atributo #!#!; isto permite crear aplicacións, como dispositivos embebidos, que queiran eliminar código dependente ou fornecer as súas propias estruturas de datos básicas.

Internamente, a biblioteca estándar divídese en tres partes: core, alloc e std, onde std e alloc son excluídas por #!#!.

Rust utiliza Option para definir valores opcionais, os cales poden ser comparados empregando if let ou match para acceder ao valor interior:fn main() {
    let name1: Option<&str> = None;
    // Neste caso, non se imprimirá nada
    if let Some(name) = name1 {
        println!("{name}");
    }

    let name2: Option<&str> = Some("Matthew");
    // Neste caso, imprimirase a palabra "Matthew"
    if let Some(name) = name2 {
        println!("{name}");
    }
}

 Punteiros 
Os tipos de referencia & e &mut garantíase que non son nulos e apuntan a memoria válida. Os tipos de punteiro cru *const e *mut non teñen estas garantías de seguridade, polo que poden ser nulos ou inválidos; con todo, é imposible desreferencialos a menos que o código se declare explicitamente como inseguro mediante o uso dun bloque unsafe. A diferenza da desreferenciación, a creación de punteiros crus está permitida dentro de código Rust seguro.

 Conversión de tipos 
Rust non prove conversión implícita de tipos (coerción) entre a maioría dos tipos primitivos. Pero pode facerse unha conversión explícita de tipo (casting) empregando a palabra clave aslet x: i32 = 1000;
println!("1000 como u16 é: {}", x as u16);

 Polymorphism 
Rust permite o polimorfismo paramétrico acoutado mediante traits e funcións xenéricas. En primeiro lugar, o comportamento común entre tipos pode declararse usando traits e impls:trait Cero: Sized {
    fn cero() -> Self;
    fn e_cero(&self) -> bool
    where
        Self: PartialEq,
    {
        self == &Cero::cero()
    }
}

impl Cero for u32 {
    fn cero() -> u32 { 0 }
}

impl Cero for f32 {
    fn cero() -> Self { 0.0 }
}O exemplo anterior tamén inclúe un método e_cero que proporciona unha implementación por defecto, polo que non é necesario definilo ao implementar o trait.

Unha función pode entón facerse xenérica engadindo parámetros de tipo dentro de chaves angulares (<Num>), que só permiten tipos que implementen o trait:// cero é unha función xenérica cun parámetro de tipo, Num
fn cero<Num: Cero>() -> Num {
    Num::cero()
}

fn main() {
    let a: u32 = cero();
    let b: f32 = cero();
    assert!(a.e_cero() && b.e_cero());
}Nos exemplos anteriores, Num: Cero así como where Self: PartialEq son restricións de traits que limitan o tipo para que só se permitan aqueles tipos que implementen Cero ou PartialEq. Dentro dun trait ou impl, Self refírese ao tipo que está a implementar o código.
Os xeréricos poden usarse en funcións para permitir implementar un comportamento para diferentes tipos sen repetir o mesmo código. As funcións xeréricas poden escribirse en relación con outros xeréricos, sen coñecer o tipo real.

 Obxectos trait 
As funcións xeréricas usan despacho estático, o que significa que o tipo de todos os parámetros que se usan na función debe ser coñecido en tempo de compilación. As funcións xeréricas xeran copias separadas do código para cada combinación de parámetros xeréricos empregada nun proceso chamado monomorfización. Debido a que a monomorfización duplica o código para cada tipo usado, o rendemento é tan bo como escribir funcións usando tipos concretos, pero o tempo de compilación e o tamaño do binario resultante poden aumentar.

Rust tamén emprega unha característica coñecida como trait objects para acadar dynamic dispatch, un tipo de polimorfismo no que a implementación dunha operación polimórfica se escolle en tempo de execución. Isto permite un comportamento semellante ao duck typing, onde todos os tipos de datos que implementen un determinado trait poden ser tratados como funcionalmente equivalentes. Os trait objects decláranse empregando a sintaxe dyn Tr, onde Tr é un trait. Os trait objects teñen tamaño dinámico, polo que deben colocarse detrás dun punteiro, como por exemplo Box. O seguinte exemplo crea unha lista de obxectos onde cada obxecto pode ser impreso empregando o trait Display:use std::fmt::Display;

let v: Vec<Box<dyn Display>> = vec![
    Box::new(3),
    Box::new(5.0),
    Box::new("ola"),
];

for x in v {
    println!("{x}");
}Se un elemento da lista non implementa o trait Display, provocará un erro en tempo de compilación.

 Seguridade da memoria 
Rust está deseñado para ser seguro na xestión da memoria. Non permite punteiros nulos, punteiros colgantes nin condicións de carreira de datos. Os valores de datos só se poden inicializar a través dun conxunto fixo de formas, todas as cales requiren que as súas entradas estean xa inicializadas.

 Administración da memoria 
Rust non emprega recollida de lixo (garbage collection). A xestión da memoria e doutros recursos faise a través da convención de “adquisición de recursos é inicialización” (RAII), con un contador de referencias opcional. Rust ofrece unha xestión determinística dos recursos, con moi baixa sobrecarga. Os valores alócanse na pila por defecto, e todas as alocacións dinámicas deben ser explícitas.
Os tipos de referencia incorporados que usan o símbolo & non implican un recuento de referencias en tempo de execución. A seguridade e validez dos punteiros subxacentes verifícanse en tempo de compilación, evitando punteiros colgantes e outras formas de comportamento indefinido. O sistema de tipos de Rust separa as referencias compartidas e inmutables do tipo &T das referencias únicas e mutables do tipo &mut T. Unha referencia mutable pode ser convertida a unha referencia inmutable, pero non ao contrario.

 Unsafe 
Rust permite realizar varias operacións inseguras mediante o uso de bloques unsafe. Isto permite aos programadores desreferenciar punteiros crus arbitrarios, chamar código externo ou executar outras funcións de baixo nivel que non están cubertas polo Rust seguro. Algunhas das funcionalidades de baixo nivel que habilita o código unsafe inclúen acceso a memoria volátil, instrínsicos específicos da arquitectura, punning de tipos e ensamblaxe en liña.
O código inseguro tamén é utilizado polos desenvolvedores para implementar estruturas de datos complexas.

 Macros 
As macros permiten xerar e transformar código en Rust para reducir a repetición. As macros existen en dúas formas: as macros declarativas, definidas mediante macro_rules!, e as macros procedimentais, que se definen en crates separados.

 Macros declarativas 
Unha macro declarativa (tamén chamada “macro por exemplo”) é unha macro definida empregando a palabra clave macro_rules!, que utiliza pattern matching para determinar a súa expansión. A continuación móstrase un exemplo que suma todos os seus argumentos:fn main() {
    // Usando `for` coa sintaxe de rango para a mesma funcionalidade que arriba
    // A sintaxe 4..=10 significa o rango de 4 a 10, ata e incluíndo o 10.
    for valor in 4..=10 {
        println!("valor = {valor}");
    }
}macro_rules! sum {
    ( $initial:expr $(, $expr:expr )* $(,)? ) => {
        $initial $(+ $expr)*
    }
}

fn main() {
    let x = sum!(1, 2, 3);
    println!("{x}"); // mostra 6
}

 Macros procedimentais 
As macros procedimentais son funcións en Rust que se executan e modifican o fluxo de tokens de entrada do compilador antes de que se compile calquera outro compoñente. Xeralmente son máis flexibles que as macros declarativas, pero son máis difíciles de manter debido á súa complexidade.

As macros procedimentais teñen tres variedades:

 Macros do tipo función: custom!(...)
 Macros derive: #[derive(CustomDerive)]
 Macros de atributo: #[custom_attribute]

 Interface con C e C++ 
Rust soporta a creación de interfaces de funcións externas (FFI) mediante a palabra clave extern. Unha función que use a convención de chamadas de C pode escribirse empregando extern "C" fn. Os símbolos poden ser exportados desde Rust a outros idiomas mediante o atributo #[no_mangle], e os símbolos poden ser importados a Rust mediante bloques extern:#[unsafe(no_mangle)]
pub extern "C" fn exportada_dende_rust(x: i32) -> i32 { x + 1 }

unsafe extern "C" {
    fn importada_en_rust(x: i32) -> i32;
}O atributo #[repr(C)] permite disposicións de memoria determinísticas para structs e enums para o seu uso a través de límites FFI. Bibliotecas externas como bindgen e cxx poden xerar enlaces (bindings) de Rust para C/C++.

 Ecosistema 
dereita|miniatura|Compilando un programa de Rust  con Cargo
O ecosistema de Rust inclúe o seu compilador, a súa biblioteca estándar e compoñentes adicionais para o desenvolvemento de software. A instalación dos compoñentes xestiónase normalmente mediante rustup, un instalador de toolchain de Rust desenvolvido polo proxecto Rust.

 Compilador 
O compilador de Rust, rustc, traduce o código Rust a LLVM IR de baixo nivel. LLVM é entón invocado como un subcompoñente para aplicar optimizacións e traducir o IR resultante a código obxecto. Despois utilízase un linker para combinar os obxectos nunha única imaxe executable ou arquivo binario.Ademais de LLVM, o compilador tamén soporta o uso de backends alternativos como GCC e Cranelift para a xeración de código. A intención destes backends alternativos é aumentar a cobertura de plataformas de Rust ou mellorar os tempos de compilación.

 Cargo 
dereita|miniatura|Screenshot de crates.io en xuño de 2022
Cargo é o sistema de compilación e xestor de paquetes de Rust. Descarga, compila, distribúe e sube paquetes—chamados crates—que se manteñen nun rexistro oficial. Tamén actúa como interface para Clippy e outros compoñentes de Rust.

Por defecto, Cargo obtén as súas dependencias do rexistro contribuído por usuarios crates.io, pero tamén se poden especificar como dependencias repositorios Git, crates no sistema de ficheiros local e outras fontes externas.

 Rustfmt 
Rustfmt é un formateador de código para Rust. Formatea espazos en branco e sangrado para producir código conforme a un estilo común, a menos que se especifique outro. Pode ser invocado como un programa independente ou desde un proxecto Rust mediante Cargo.

 Clippy 
dereita|miniatura|Exemplo de saída de Clippy sobre un programa Rust de 'ola mundo'
Clippy é a ferramenta de linting integrada de Rust para mellorar a corrección, o rendemento e a lexibilidade do código Rust. A partir de 2024, conta con máis de 700 regras.

 Sistema de control de versións 
Tras Rust 1.0, as novas funcionalidades desenvolvéronse nas versións nightly, que se publican diariamente. Durante cada ciclo de lanzamento de seis semanas, os cambios das versións nightly publícanse na versión beta, mentres que os cambios da versión beta anterior publícanse nunha nova versión estable.

Cada dous ou tres anos, publícase unha nova “edición”. As edicións lévanse a cabo para permitir realizar cambios rompentes limitados, como promover await a unha palabra clave para soportar funcionalidades async/await. Os crates orientados a distintas edicións poden interoperar entre si, polo que un crate pode actualizarse a unha nova edición mesmo se os seus chamadores ou as súas dependencias aínda apuntan a edicións anteriores. A migración a unha nova edición pode asistirse con ferramentas automáticas.

 Soporte de IDE 
Rust-analyzer é un conxunto de utilidades que proporciona ás contornas de desenvolvemento integrados (IDEs) e editores de texto información sobre un proxecto Rust mediante o Language Server Protocol. Isto habilita funcionalidades como autocompletado e visualización de erros de compilación mentres se edita o código.

 Rendemento 
Como non realiza recollida de lixo (garbage collection), Rust é a miúdo máis rápido que outros idiomas seguros na xestión de memoria. A maior parte das garantías de seguridade de memoria de Rust non impoñen sobrecarga en tempo de execución, agás a indexación de arrays, que por defecto se comproba en tempo de execución. O impacto no rendemento das comprobacións de límites de arrays varía, pero pode ser significativo en algúns casos.

Moitas das funcionalidades de Rust son chamadas abstraccións de custo cero, o que significa que se optimizan en tempo de compilación e non supoñen penalización en tempo de execución. O sistema de propiedade e préstamo permite implementacións sen copias para certas tarefas sensibles ao rendemento, como o parsing. Por defecto utilízase static dispatch para eliminar chamadas a métodos, agás para métodos chamados sobre obxectos trait dinámicos. O compilador tamén emprega expansión en liña para eliminar chamadas a funcións e invocacións de métodos despachadas estaticamente.

Como Rust usa LLVM, todas as melloras de rendemento en LLVM tamén se aplican a Rust. Ao contrario que C e C++, Rust permite reordenar os elementos de structs e enums para reducir o tamaño das estruturas na memoria, mellorando o aliñamento e a eficiencia da memoria.

 Adopción 
dereita|miniatura|150x150px|Firefox ten compoñentes escritos en Rust como parte do motor de navegador subxacente Gecko.
Rust úsase en software en distintos ámbitos. Compoñentes do motor de navegador Servo (financiado por Mozilla e Samsung) foron incorporados no motor de navegador Gecko, que subxace en Firefox. En xaneiro de 2023, Google (Alphabet) anunciou soporte para usar librarías Rust de terceiros en Chromium.

Rust úsase en varios proxectos de software de backend de grandes servizos web. OpenDNS, un servizo de resolución DNS propiedade de Cisco, utiliza Rust internamente. Amazon Web Services emprega Rust en “compoñentes sensibles ao rendemento” de varios dos seus servizos. En 2019, AWS liberou como código aberto Firecracker, unha solución de virtualización escrita principalmente en Rust. Microsoft Azure IoT Edge, unha plataforma usada para executar servizos de Azure en dispositivos IoT, ten compoñentes implementados en Rust. Microsoft tamén emprega Rust para executar módulos conteinerizados con WebAssembly e Kubernetes. Cloudflare, unha compañía que ofrece servizos de rede de distribución de contidos, utilizou Rust para construír un novo proxy web chamado Pingora, mellorando o rendemento e a eficiencia. O xestor de paquetes npm utilizou Rust para o seu servizo de autenticación en produción en 2019.
miniatura|150x150px|O proxecto Rust para Linux está soportado no núcleo Linux desde 2022.
Nos sistemas operativos, o proxecto Rust para Linux, lanzado en 2020, fusionou o soporte inicial no núcleo Linux versión 6.1 a finais de 2022. O proxecto está activo cun equipo de 6–7 desenvolvedores e engadiu máis código en Rust coas versións do núcleo de 2022 a 2024, co obxectivo de demostrar a viabilidade mínima do proxecto e resolver bloqueos clave de compatibilidade. Os primeiros controladores escritos en Rust foron fusionados no núcleo para a versión 6.8. Os desenvolvedores de Android empregaron Rust en 2021 para reescribir compoñentes existentes. Microsoft reescribiu partes de Windows en Rust. O proxecto r9 pretende reimplementar Plan 9 de Bell Labs en Rust. Rust tamén se empregou no desenvolvemento de novos sistemas operativos como Redox, un sistema operativo e microkernel “Unix-like”, Theseus, un sistema operativo experimental con xestión modular do estado, e a maior parte de Fuchsia. Rust tamén se usa para ferramentas de liña de comandos e compoñentes de sistemas operativos, incluíndo stratisd, un xestor de sistemas de ficheiros, e COSMIC, un escritorio desenvolvido por System76. No desenvolvemento web, Deno, unha contorna segura de execución para JavaScript e TypeScript, está construída sobre V8 empregando Rust e Tokio. Outras adopcións notables neste ámbito inclúen Ruffle, un emulador SWF de código aberto, e Polkadot, unha plataforma de blockchain e criptomoeda de código aberto.

Discord, unha empresa de software de mensaxería instantánea, reescribiu partes do seu sistema en Rust para aumentar o rendemento en 2020. No mesmo ano, Dropbox anunciou que a súa sincronización de ficheiros fora reescrita en Rust. Facebook (Meta) utilizou Rust para redeseñar o seu sistema que xestiona o código fonte dos proxectos internos.

Na enquisa a desenvolvedores de Stack Overflow de 2024, o 12,6 % dos entrevistados realizara recentemente un desenvolvemento extensivo en Rust. A enquisa nomeou a Rust como a “linguaxe de programación máis admirada” anualmente de 2016 a 2024 (inclusive), medida polo número de desenvolvedores existentes interesados en continuar traballando coa linguaxe. En 2024, o 28,7 % dos desenvolvedores que actualmente non traballan con Rust expresaron interese en facelo.

DARPA ten un proxecto chamado TRACTOR (Translating All C to Rust) que traduce automaticamente C a Rust empregando técnicas como análise estática, análise dinámica e modelos de linguaxe grande.

 Na investigación académica 
A seguridade e o rendemento de Rust foron investigados en investigacións sobre teoría das linguaxes de programación.
A aplicabilidade de Rust para escribir software de investigación examinouse noutros campos. Un artigo publicado nos Proceedings of the International Astronomical Union utilizou Rust para simular sistemas de múltiples planetas. Un artigo publicado en Nature compartiu historias de bioinformáticos que empregan Rust. Ambos os artigos concluíron que Rust presenta vantaxes polo seu rendemento e seguridade, e citaron a curva de aprendizaxe como a principal desvantaxe para a súa adopción.

 Comunidade 
alt=A bright orange crab icon|miniatura|Algúns usuarios de Rust refírense a si mesmos como Rustaceans (semellante á palabra crustacean) e adoptaron un cangrexo laranxa, Ferris, como mascota non oficial.
Segundo a MIT Technology Review, a comunidade de Rust foi considerada “infrecuentemente amigable” para os novos membros e atraeu particularmente a persoas da comunidade queer, en parte debido ao seu código de conduta, que establecía un conxunto de expectativas que os membros da comunidade Rust debían seguir. A inclusión na comunidade foi citada como un factor importante por algúns desenvolvedores de Rust. Datos demográficos sobre a comunidade foron recollidos e publicados no blog oficial de Rust.

Segundo o proxecto State of the Octoverse de GitHub, a comunidade de Rust medrou un 50,5 % en 2022, converténdoa nunha das comunidades de máis rápido crecemento, aínda que non está entre as 10 comunidades máis grandes a partir de 2024.

 Fundación Rust 
fn main() {
    let x = 5;                // ------------------+- Tempo de vida 'a
                              //                   |
    let r = &x;               // -+-- Tempo de vida 'b  |
                              //  |                |
    println!("r: {}", r);     //  |                |
                              //  |                |
                              // -+                |
}                             // ------------------+A Rust Foundation é unha organización sen ánimo de lucro con membros incorporada nos Estados Unidos, cuxos principais obxectivos son apoiar o proxecto técnico como entidade legal e axudar a xestionar a marca rexistrada e os activos de infraestrutura.

Foi establecida o 8 de febreiro de 2021, con cinco membros corporativos fundadores (Amazon Web Services, Huawei, Google, Microsoft e Mozilla). O consello da fundación está presidido por Shane Miller. Desde finais de 2021, a súa Directora Executiva e CEO é Rebecca Rumbul. Antes diso, Ashley Williams foi directora executiva interina.

 Equipos de gobernanza 
O proxecto Rust está composto por equipos responsables de diferentes subáreas do desenvolvemento. O equipo do compilador desenvolve, xestiona e optimiza os elementos internos do compilador; e o equipo de linguaxe deseña novas funcionalidades da linguaxe e axuda a implementalas. O sitio web do proxecto Rust lista 6 equipos de nivel superior a partir de xullo de 2024. Representantes dos distintos equipos forman o Consello de Liderado, que supervisa o proxecto Rust no seu conxunto.

 Notas 

 Referencias 

 Véxase tamén 
 Bibliografía 







 Ligazóns externas 
 Web oficial
 Código fonte en GitHub

Categoría:Linguaxes de programación
Categoría:Mozilla