Aprender sobre estos dos conceptos ayudará a reforzar su comprensión de cómo funciona Rust y cómo puede implementar las características de OOP.

Los rasgos y la duración son componentes clave de Rust. Puede usar rasgos para definir comportamientos y capacidades para que los tipos los implementen. Son muy versátiles, lo que le permite escribir código más genérico, reducir la duplicación y mejorar la capacidad de mantenimiento.

Rust utiliza otro mecanismo, la vida útil, para rastrear la propiedad de las variables dentro y fuera del alcance. Esto evita punteros colgantes durante la desasignación de variables.

Juntos, los rasgos y la duración ayudan a garantizar la seguridad de los tipos, la seguridad de la memoria y la confiabilidad del código.

Comprender los rasgos en Rust

Los rasgos son colecciones de métodos que otros tipos pueden implementar. Los rasgos son similares a interfaces en lenguajes como Java, Go y TypeScript, pero más flexibles.

Usarás el rasgo palabra clave para definir características en Rust, seguida de una declaración de firmas de métodos.

rasgomi rasgo {
fnmi_método(&ser);
}

El código define un rasgo llamado mi rasgo con un mi_método método. El &ser El parámetro indica que el método se refiere al objeto del tipo de implementación como su primer parámetro.

Después de definir un rasgo, puede implementarlo para sus tipos personalizados.

Así es como puede implementar un rasgo para sus tipos de estructura.

estructuraPersona {
nombre: Cadena,
edad: u32,
}

impl Información para Persona {
fnresumen(&ser) {
imprimir!("Mi nombre es {} y tengo {} años"., ser.nombre, ser.edad);
}
}

El Persona implementos de estructura Información, y puedes llamar al resumen método en instancias del Persona estructura

fnprincipal(){
dejar juan = Persona { nombre: Cadena::de("John"), edad: 30 };
juan.resumen(); // Salida: Mi nombre es John y tengo 30 años.
}

El John variable es una instancia de la Persona estructura

El principal llamadas de función resumen que imprime un mensaje a la consola:

Las enumeraciones pueden implementar rasgos. Así es como puede definir una enumeración con variantes que implementan el resumen método:

enumeraciónMi Enum {
varianteA,
varianteB,
}

impl Información para MiEnum {
fnresumen(&ser) {
fósforoser {
MiEnumeración:: VarianteA => {
// implementación para VariantA
}
MiEnumeración:: VarianteB => {
// implementación para VariantB
}
}
}
}

Uso de rasgos para parámetros de función y valores devueltos

Puede usar rasgos como parámetros de función y valores de retorno. El uso de rasgos como parámetros de función es útil para escribir código genérico con varios tipos.

Aquí hay una función que toma un parámetro de cualquier tipo que implementa Información.

fnhacer algo(valor: T) {
valor.resumen();
}

El la sintaxis especifica que T debe implementar Información. Puedes llamar al resumen función con cualquier valor que implemente Información.

Vidas en Rust

La herramienta de verificación de préstamos de Rust analiza los programas y garantiza el uso adecuado de la memoria. en óxido, todo valor tiene un dueño que es responsable de desasignar el valor. Cuando valores prestados de las variables, toman prestada una referencia al valor pasado, pero el propietario conserva la propiedad.

Los tiempos de vida son una forma de garantizar que los valores prestados se utilicen correctamente. Una vida útil es una etiqueta adjunta a una referencia que describe cuánto tiempo es válida la referencia.

En Rust, puede especificar una vida útil usando una anotación de apóstrofe:

función<'a>

Al crear una referencia, a la referencia se le asigna un tiempo de vida que describe cuánto tiempo es válida. Si tiene una función que toma la referencia a un valor, la vida útil debe ser más larga que la llamada a la función para garantizar que el valor sea válido cuando la función regrese.

Aquí hay un ejemplo de especificación de tiempo de vida en una función.

fnhacer algo<'a>(x: &'ai32) -> &'ai32 {
X
}

fnprincipal() {
dejar x = 42;
dejar resultado = hacer_algo(&x);
imprimir!("El resultado es: {}", resultado);
}

En el hacer algo función, la 'a El parámetro de duración indica que la referencia a X es válido mientras la función llame. La referencia devuelta también es válida mientras la función llame.

El principal La función imprime el resultado pasando una referencia al X variables en el principal función a la consola.

La sintaxis de por vida puede ser detallada, pero es esencial para la seguridad y la gestión de la memoria. Las reglas de elisión de tres vidas proporcionan pautas que permiten a Rust inferir la vida útil de las referencias en ciertas situaciones.

La regla de vida útil de entrada

La regla de vigencia de entrada especifica que si una función o método toma una o más referencias como parámetros de entrada, Rust asume que todas las referencias tienen la misma vigencia.

En pocas palabras, la vida útil de las referencias de salida será la misma que la de las referencias de entrada.

fnmás largo<'a>(x: &'acalle, y: &'acalle) -> &'acalle {
si x.len() > y.len() { x } demás { y }
}

En el más largo función, Rust infiere que la vida útil de la referencia de salida es la misma que la referencia de entrada porque ambas tienen el mismo parámetro de vida útil 'a.

La regla de duración de entrada facilita la escritura de funciones genéricas que toman múltiples referencias como entrada.

La regla de vida útil de salida

La regla de vida útil de salida especifica que si una función o método devuelve una referencia, Rust supondrá que la vida útil de la referencia de salida es diferente de la vida útil de cualquier referencia de entrada.

fnprimera palabra<'a>(s: &'acalle) -> &'acalle {
s.split_whitespace().next().unwrap()
}

En esta función, Rust infiere que el tiempo de vida de la referencia de salida es diferente del tiempo de vida de la referencia de entrada porque el dividir_espaciosenblanco() El método crea una referencia de salida que no toma parámetros de referencia de entrada.

La regla de elisión de vidas

La regla de elisión de tiempos de vida se aplica si una función o método toma una referencia o un parámetro de entrada y devuelve una referencia. En ese caso, Rust asume que la referencia de salida tiene el mismo tiempo de vida que la referencia de entrada.

fnmás largo<'a>(x: &'acalle, y: &calle) -> &'acalle {
si x.len() > y.len() { x } demás { y }
}

En esta función, Rust infiere que la vida útil de la referencia de salida es la misma que la vida útil de la referencia de entrada porque la referencia de entrada y no tiene parámetro de por vida. Rust elude el parámetro de vida útil para y y asume que tiene la misma vida útil que X.

Esta regla facilita la escritura de funciones que toman una referencia de entrada y devuelven una referencia de salida.

Rasgos y vidas

Puede combinar rasgos y tiempos de vida para crear funciones genéricas que funcionen para tipos que implementan un rasgo y tienen un tiempo de vida válido.

Aquí hay un rasgo y una función que hace referencia a un valor que implementa el rasgo.

rasgoEncadenar {
fnEncadenar(&ser) -> Cadena;
}

fnEncadenar<'a, T: Encadenar>(t: &'a T) -> Cadena {
t.a_cadena()
}

Aquí, el parámetro de por vida 'a asegura que la referencia t es válido durante la vida útil del objeto al que hace referencia. Puedes usar el Encadenar función con tipos que implementan el Encadenar rasgo que tiene una vida útil válida.

Los rasgos forman la base para implementar conceptos OOP en Rust

Los rasgos le permiten definir comportamientos. Aunque Rust no es un lenguaje de programación orientado a objetos (OOP), puede usar rasgos para implementar conceptos de OOP desde la encapsulación hasta la herencia, el polimorfismo y la abstracción.

La implementación de estos conceptos OOP con rasgos hace que sus programas Rust sean escalables, robustos, fáciles de mantener y eficientes.