Anuncios

Bienvenidos sean a este post, hoy veremos como se implementa realmente a struct.

Anuncios

En el post anterior vimos una forma practica de definir un par de struct para nuestro codigo pero en la vida real tendremos unos mas grandes y en mayor cantidad, lo cual hara a nuestro archivo main.rs impractico, para resolver esto se crea un archivo por cada struct y luego los incluiremos desde el main para implementarlo, para ello tomaremos el ejemplo que vimos en el post anterior y lo modificaremos.

Anuncios

Para ello dentro de nuestro directorio src vamos a crear dos nuevos archivos, el primero lo llamaremos area.rs y le agregaremos el siguiente codigo:

area.rs

struct Area
{
        oficina: String,
        puesto: String,
}
Anuncios

Lo que hicimos fue simplemente poner el codigo de nuestro struct encargado de almacenar los datos del area de la persona o usuario, pasemos a crear el siguiente archivo que llamaremos persona.rs y le agregaremos el siguiente codigo:

persona.rs

include!("area.rs");

struct Persona
{
        nombre: String,
        edad: i32,
        apellido: String,
	area: Area,
}
Anuncios

En este caso volvemos a hacer lo anterior agregando el struct persona pero en este tenemos una nueva instruccion o macro llamada include, esta nos permite incluir el archivo que le informemos para poder utilizar el contenido del mismo, en este caso para poder acceder al struct area y poder usarlo en el nuestro, con esto comentado pasemos a main.rs y reemplacemos el codigo actual con el siguiente:

main.rs

include!("persona.rs");

fn main() 
{
	let usuario = Persona {
		nombre: String::from("Martin"),
		apellido: String::from("Miranda"),
		edad: 45,
		area: Area{
			oficina: String::from("IT"),
			puesto: String::from("Desarrollador")
			},
		};

	println!("Nombre: {}", usuario.nombre);
	println!("Apellido: {}", usuario.apellido);
	println!("Edad: {}", usuario.edad);
	println!("Oficina: {}", usuario.area.oficina);
	println!("Puesto: {}", usuario.area.puesto);	
}
Anuncios

En el post anterior comentamos sobre este codigo pero basicamente se crea un objeto del struct persona para completar todos sus datos y por ultimo lo mostramos en pantalla, la diferencia esta con respecto al codigo anterior que en lugar de tener los struct pasamos la macro include seguido de la ultima struct que creamos, si lo compilamos y probamos veremos la siguiente salida:

tinchicus@dbn001vrt:~/lenguajes/rust/estructura$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/estructura`
Nombre: Martin
Apellido: Miranda
Edad: 45
Oficina: IT
Puesto: Desarrollador
tinchicus@dbn001vrt:~/lenguajes/rust/estructura$
Anuncios

Si bien podemos implementarlo de esta forma, no es la correcta dado que nos saca de uso algunas opciones que podemos necesitar para nuestros codigos, la forma correcta de implementarlo es a traves de mod y use, para ello debemos hacer un par de cambios en el codigo y en la estructura del proyecto, lo primero que haremos es crear un nuevo directorio dentro de src al cual llamaremos persona, una vez creado generaremos dos archivos nuevos, el primero se llamara mod.rs y le agregaremos el siguiente codigo:

mod.rs

mod area;
use area::*;

struct Persona
{
        nombre: String,
        edad: i32,
        apellido: String,
        area: Area,
}
Anuncios

Es muy similar al que vimos en persona.rs pero la diferencia radica que quitamos la macro include y agregamos el siguiente bloque:

mod area;
use area::*;
Anuncios

En la primera linea es para decirle que importe el modulo llamado area, la segunda es para usar todo el contenido del modulo area en nuestro codigo, el resto es la misma struct que antes, nuestro siguiente paso es crear otro archivo dentro de este directorio y lo llamaremos area.rs, a este archivo le agregaremos el siguiente codigo:

area.rs

struct Area
{
        oficina: String,
        puesto: String,
}
Anuncios

Este es simplemente el modulo que cargaremos para el otro y asi poder tener acceso a la informacion que se necesita, lo siguiente sera eliminar los archivos persona.rs y area.rs que tenemos en el raiz del directorio src (o pueden renombrarlo con la extension .old) para evitar tener conflictos al momento de compilarlo, por ultimo debemos modificar a main.rs de la siguiente manera:

main.rs

mod persona;
use persona::*;

fn main() 
{
	let usuario = Persona {
		nombre: String::from("Martin"),
		apellido: String::from("Miranda"),
		edad: 45,
		area: Area{
			oficina: String::from("IT"),
			puesto: String::from("Desarrollador")
			},
		};

	println!("Nombre: {}", usuario.nombre);
	println!("Apellido: {}", usuario.apellido);
	println!("Edad: {}", usuario.edad);
	println!("Oficina: {}", usuario.area.oficina);
	println!("Puesto: {}", usuario.area.puesto);	
}
Anuncios

De vuelta la unica modificacion que hacemos con respecto al codigo anterior es la eliminacion de la macro por un llamado de mod a persona, el modulo que generamos anteriormente, y le decimos que vamos a utilizar todo el contenido dentro de este y a su vez incluira todo el contenido de area, compilemos y veamos su salida:

tinchicus@dbn001vrt:~/lenguajes/rust/estructura$ cargo build
   Compiling estructura v0.1.0 (/home/tinchicus/lenguajes/rust/estructura)
error[E0412]: cannot find type `Area` in this scope
 --> src/persona/mod.rs:9:15
  |
9 |         area: Area,
  |               ^^^^ not found in this scope
  |

note: struct `crate::persona::area::Area` exists but is inaccessible
 --> src/persona/area.rs:1:1
  |
1 | struct Area
  | ^^^^^^^^^^^ not accessible

error[E0422]: cannot find struct, variant or union type `Persona` in this scope
 --> src/main.rs:6:16
  |
6 |     let usuario = Persona {
  |                   ^^^^^^^ not found in this scope
  |
note: struct `crate::persona::Persona` exists but is inaccessible
 --> src/persona/mod.rs:4:1
  |
4 | struct Persona
  | ^^^^^^^^^^^^^^ not accessible

error[E0422]: cannot find struct, variant or union type `Area` in this scope
  --> src/main.rs:10:9
   |
10 |         area: Area{
   |               ^^^^ not found in this scope
   |
note: struct `crate::persona::area::Area` exists but is inaccessible
  --> src/persona/area.rs:1:1
   |
1  | struct Area
   | ^^^^^^^^^^^ not accessible

warning: unused import: `area::*`
 --> src/persona/mod.rs:2:5
  |
2 | use area::*;
  |     ^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused import: `persona::*`
 --> src/main.rs:2:5
  |
2 | use persona::*;
  |     ^^^^^^^^^^

Some errors have detailed explanations: E0412, E0422.
For more information about an error, try `rustc --explain E0412`.
warning: `estructura` (bin "estructura") generated 2 warnings
error: could not compile `estructura` due to 3 previous errors; 2 warnings emitted
tinchicus@dbn001vrt:~/lenguajes/rust/estructura$
Anuncios
Anuncios

Oh, que paso? Aca entra en juego uno de los temas mas importantes en todo lenguaje como son los modificadores de acceso, estos permiten o no que algunas partes del codigo sean accesibles para todo el resto del codigo o no, de manera predeterminada el codigo toma todo como privado, por lo tanto todo lo que este por fuera del struct no podra ser accedida salvo que lo convertamos en publico, para ello debemos usar la palabra pub para cada cosa, vamos a modificar primero el archivo area.rs de la siguiente forma:

area.rs

pub struct Area
{
        pub oficina: String,
        pub puesto: String,
}
Anuncios

Si lo comparan con el codigo anterior veran que lo unico que se modifico es el tipo de acceso a todos los elementos, ya sea desde el struct hasta las variables internas porque como dijimos estan tambien son privadas pero necesitaremos acceder a ellas desde el main, pasemos al siguiente archivo llamado mod.rs y lo modificaremos de la siguiente manera:

mod area;
use area::*;

pub struct Persona
{
        pub nombre: String,
        pub edad: i32,
        pub apellido: String,
        pub area: Area,
}
Anuncios

Aqui sucede lo mismo, debemos agregar el pub tanto al struct como a las variables internas de lo contrario nos informara que no tenemos acceso, con todo esto modificado veamos como es su salida:

tinchicus@dbn001vrt:~/lenguajes/rust/estructura$ cargo build
   Compiling estructura v0.1.0 (/home/tinchicus/lenguajes/rust/estructura)
error[E0422]: cannot find struct, variant or union type `Area` in this scope
  --> src/main.rs:10:9
   |
10 |         area: Area{
   |               ^^^^ not found in this scope
   |
note: struct `crate::persona::Area` exists but is inaccessible
  --> src/persona/area.rs:1:1
   |
1  | pub struct Area
   | ^^^^^^^^^^^^^^^ not accessible

For more information about this error, try `rustc --explain E0422`.
error: could not compile `estructura` due to previous error
tinchicus@dbn001vrt:~/lenguajes/rust/estructura$
Anuncios

Y ahora?, por que sigue fallando? Esto es debido a lo que comentamos antes, todas las lineas se consideran como privadas mientras no las hagamos publicas, por lo tanto cuando desde el main intente acceder al struct area este intenta usar el mod en mod.rs pero como es privado no se lo permite usar por lo tanto esta fuera de su rango para solucionarlo debemos ir a mod.rs y modifiquemos estas lineas:

mod area;
use area::*;
Anuncios

De la siguiente manera:

pub mod area;
pub use area::*;
Anuncios

Esto nos permitira ahora si acceder a la struct que es parte de la otra, con todo esto comentado vamos a compilar y ver su salida:

tinchicus@dbn001vrt:~/lenguajes/rust/estructura$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/estructura`
Nombre: Martin
Apellido: Miranda
Edad: 45
Oficina: IT
Puesto: Desarrollador
tinchicus@dbn001vrt:~/lenguajes/rust/estructura$
Anuncios
Anuncios

Como pueden ver ahora funciono perfectamente, esto nos es util para cuando necesitamos que ciertas partes del codigo queden restringuidas porque una modificacion en ella puede ocasionar un error fatal que nos cierre la aplicacion, por esta razon es mejor usar esta forma que la macro include, si bien es mas engorroso con practica esto se vuelve mas natural a la hora de desarrollar, ahora vamos a suponer que necesitamos agregar la nomina para la persona o usuario, para ello vamos a crear un nuevo archivo que llamaremos nomina.rs dentro del directorio persona y le agregaremos el siguiente codigo:

nomina.rs

pub struct Nomina
{
	pub bruto: i32,
	pub neto: i32,
}
Anuncios

Como pueden ver vamos a almacenar dos valores, uno para el sueldo bruto (lo que le paga la empresa) y el neto (lo que realmente recibe con los descuentos), con estos dos valores lo siguiente sera modificar a mod.rs de la siguiente manera:

mod.rs

pub mod area;
pub use area::*;
pub mod nomina;
pub use nomina::*;

pub struct Persona
{
        pub nombre: String,
        pub edad: i32,
        pub apellido: String,
        pub area: Area,
	pub sueldo: Nomina,
}
Anuncios

En este caso simplemente agregamos el nuevo mod con el nuevo use para el nuevo struct que creamos de forma muy similar a la vista y por ultimo agregamos una nueva linea dentro del struct donde ahora se almacena el sueldo, nuestro siguiente paso sera modificar el main.rs con el siguiente codigo:

main.rs

mod persona;
use persona::*;

fn main() 
{
	let usuario = Persona {
		nombre: String::from("Martin"),
		apellido: String::from("Miranda"),
		edad: 45,
		area: Area{
			oficina: String::from("IT"),
			puesto: String::from("Desarrollador")
			},
		sueldo: Nomina{
			bruto: 30000,
			neto: 20000,
			},
		};
	
	println!("Nombre: {}", usuario.nombre);
	println!("Apellido: {}", usuario.apellido);
	println!("Edad: {}", usuario.edad);
	println!("Oficina: {}", usuario.area.oficina);
	println!("Puesto: {}", usuario.area.puesto);	
	println!("Sueldo Bruto: {}", usuario.sueldo.bruto);
	println!("Sueldo Neto: {}", usuario.sueldo.neto);
}
Anuncios

En este caso son pocas las modificaciones con respecto al codigo anterior, la primera sera el agregado de la variable sueldo donde le pasamos a Nomina y luego los valores para las variables internas, por ultimo agregamos dos lineas mas para que pueda mostrar los nuevos valores que agregamos, el resto sigue exactamente de la misma forma, compilemos y veamos su salida:

tinchicus@dbn001vrt:~/lenguajes/rust/estructura$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/estructura`
Nombre: Martin
Apellido: Miranda
Edad: 45
Oficina: IT
Puesto: Desarrollador
Sueldo Bruto: 30000
Sueldo Neto: 20000
tinchicus@dbn001vrt:~/lenguajes/rust/estructura$
Anuncios

Ahora vamos a ver una ultima propiedad que nos permite struct como es el compartir informacion entre distintas instancias, para ello debemos ir al archivo main.rs donde modificaremos el codigo, para ello despues de la creacion del objeto agregaremos el siguiente bloque:

	let usuario2 = Persona {
		nombre: String::from("Enzo"),
		apellido: String::from("Tortore"),
		edad: 33,
		area: Area{
			oficina: String::from("DB"),
			puesto: String::from("Administrador")
			},
		sueldo: Nomina{
			bruto: usuario.sueldo.bruto,
			neto: usuario.sueldo.neto,
			},
		};
Anuncios
Anuncios

Observen que generamos otro objeto o mejor dicho otro usuario, con sus respectivos datos y si bien son distintos vamos a considerar que tiene el mismo sueldo que el usuario anterior, por lo tanto en lugar de pasarle el valor le pasamos los valores anteriormente creados, para ello le pasamos todo el path o camino donde se encuentra, esto no se puede hacer con los tipos string pero si se puede con otra forma de la cual hablaremos mas adelante, siguiendo con nuestro codigo lo siguiente sera agregar el siguiente bloque despues de cuando mostramos los datos del primer usuario:

	println!();
        println!("Nombre: {}", usuario2.nombre);
        println!("Apellido: {}", usuario2.apellido);
        println!("Edad: {}", usuario2.edad);
        println!("Oficina: {}", usuario2.area.oficina);
        println!("Puesto: {}", usuario2.area.puesto);
        println!("Sueldo Bruto: {}", usuario2.sueldo.bruto);
        println!("Sueldo Neto: {}", usuario2.sueldo.neto);
Anuncios

Este bloque es el encargado de mostrar todos los datos sobre el nuevo usuario creado, antes de compilarlo veamos como quedo el archio main.rs:

main.rs

mod persona;
use persona::*;

fn main() 
{
	let usuario = Persona {
		nombre: String::from("Martin"),
		apellido: String::from("Miranda"),
		edad: 45,
		area: Area{
			oficina: String::from("IT"),
			puesto: String::from("Desarrollador")
			},
		sueldo: Nomina{
			bruto: 30000,
			neto: 20000,
			},
		};

	let usuario2 = Persona {
		nombre: String::from("Enzo"),
		apellido: String::from("Tortore"),
		edad: 33,
		area: Area{
			oficina: String::from("DB"),
			puesto: String::from("Administrador")
			},
		sueldo: Nomina{
			bruto: usuario.sueldo.bruto,
			neto: usuario.sueldo.neto,
			},
		};

	println!("Nombre: {}", usuario.nombre);
	println!("Apellido: {}", usuario.apellido);
	println!("Edad: {}", usuario.edad);
	println!("Oficina: {}", usuario.area.oficina);
	println!("Puesto: {}", usuario.area.puesto);	
	println!("Sueldo Bruto: {}", usuario.sueldo.bruto);
	println!("Sueldo Neto: {}", usuario.sueldo.neto);
	println!();
        println!("Nombre: {}", usuario2.nombre);
        println!("Apellido: {}", usuario2.apellido);
        println!("Edad: {}", usuario2.edad);
        println!("Oficina: {}", usuario2.area.oficina);
        println!("Puesto: {}", usuario2.area.puesto);
        println!("Sueldo Bruto: {}", usuario2.sueldo.bruto);
        println!("Sueldo Neto: {}", usuario2.sueldo.neto);
}
Anuncios

Con esto comentado veamos como es nuestra nueva salida:

tinchicus@dbn001vrt:~/lenguajes/rust/estructura$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/estructura`
Nombre: Martin
Apellido: Miranda
Edad: 45
Oficina: IT
Puesto: Desarrollador
Sueldo Bruto: 30000
Sueldo Neto: 20000

Nombre: Enzo
Apellido: Tortore
Edad: 33
Oficina: DB
Puesto: Administrador
Sueldo Bruto: 30000
Sueldo Neto: 20000
tinchicus@dbn001vrt:~/lenguajes/rust/estructura$
Anuncios

Como pueden ver nos recupero la informacion previa sobre el sueldo pero recuerden que los tipo string no se pueden hacer asi pero ya veremos como implementarlo mas adelante, por ultimo veamos la estructura final del proyecto:

tinchicus@dbn001vrt:~/lenguajes/rust/estructura$ tree
.
├── Cargo.lock
├── Cargo.toml
└── src
    ├── main.rs
    └── persona
        ├── area.rs
        ├── mod.rs
        └── nomina.rs

2 directories, 6 files
tinchicus@dbn001vrt:~/lenguajes/rust/estructura$
Anuncios

Pasemos a ver los codigos finales de este proyecto:

main.rs

mod persona;
use persona::*;

fn main() 
{
	let usuario = Persona {
		nombre: String::from("Martin"),
		apellido: String::from("Miranda"),
		edad: 45,
		area: Area{
			oficina: String::from("IT"),
			puesto: String::from("Desarrollador")
			},
		sueldo: Nomina{
			bruto: 30000,
			neto: 20000,
			},
		};

	let usuario2 = Persona {
		nombre: String::from("Enzo"),
		apellido: String::from("Tortore"),
		edad: 33,
		area: Area{
			oficina: String::from("DB"),
			puesto: String::from("Administrador")
			},
		sueldo: Nomina{
			bruto: usuario.sueldo.bruto,
			neto: usuario.sueldo.neto,
			},
		};
	
	println!("Nombre: {}", usuario.nombre);
	println!("Apellido: {}", usuario.apellido);
	println!("Edad: {}", usuario.edad);
	println!("Oficina: {}", usuario.area.oficina);
	println!("Puesto: {}", usuario.area.puesto);	
	println!("Sueldo Bruto: {}", usuario.sueldo.bruto);
	println!("Sueldo Neto: {}", usuario.sueldo.neto);
	println!();
	println!("Nombre: {}", usuario2.nombre);
	println!("Apellido: {}", usuario2.apellido);
	println!("Edad: {}", usuario2.edad);
	println!("Oficina: {}", usuario2.area.oficina);
	println!("Puesto: {}", usuario2.area.puesto);
	println!("Sueldo Bruto: {}", usuario2.sueldo.bruto);
	println!("Sueldo Neto: {}", usuario2.sueldo.neto);
}
Anuncios

persona/mod.rs

pub mod area;
pub use area::*;
pub mod nomina;
pub use nomina::*;

pub struct Persona
{
        pub nombre: String,
        pub edad: i32,
        pub apellido: String,
        pub area: Area,
	pub sueldo: Nomina,
}
Anuncios

persona/area.rs

pub struct Area
{
        pub oficina: String,
        pub puesto: String,
}
Anuncios

persona/nomina.rs

pub struct Nomina
{
	pub bruto: i32,
	pub neto: i32,
}
Anuncios

En resumen, hoy hemos visto como se usa realmente struct, hemos visto como implementarlo primero mediante include, luego por medio de mod y use, seguido vimos el inconveniente que tenemos por como Rust trabaja con los permisos de acceso, hemos visto como solucionarlos y por ultimo un uso practico de reutilizacion de informacion previa, espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios
pp258

Donación

Es para mantenimento del sitio, gracias!

$1.50