Anuncios

Bienvenidos sean a este post, hoy hablaremos sobre la segunda clave de como manejar las variables.

Anuncios
Anuncios

Ya hablamos sobre las propiedades o la union entre la ubicacion en memoria del valor y la variable, ya vimos que en tipos primitivos se realiza un copy trait y este nos permite tener una copia del valor sin vulnerar la regla de que dos objetos apunten a la misma direccion de memoria, si volvemos en el tiempo en este post hablamos sobre como son las referencias y resumiendo dijimos que son la copia a un apuntador de una ubicacion de memoria, siendo esto una gran parte del borrowing o «pedir prestado» si lo traducimos a nuestro idioma.

Anuncios

En el post anterior creamos un ejemplo que llamamos copiar y al archivo main.rs le agregamos el siguiente codigo:

main.rs

fn sumar(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32)
{
	let sum = v1.iter().fold(0i32, |a, &b| a + b);
	let prod = v2.iter().fold(1i32, |a, &b| a * b);
	return (v1, v2, sum + prod);
}

fn main() 
{
	let vecuno = vec![2, 3, 5];
	let vecdos = vec![3, 5];
	let(vecuno, vecdos, rta) = sumar(vecuno, vecdos);
	println!("{}", vecuno[0]);
	println!("{}", vecdos[0]);
	println!("{}",rta);
}
Anuncios

Para entender bien el codigo les recomiendo visitar el post anterior pero basicamente la verdadera magia la hace el tuple que recibe los datos que enviamos de la funcion sumar donde basicamente volvemos a reasignar la propiedad, dijimos en el post anterior que esto se podia mejorar, para ello vamos a modificar el codigo de la siguiente manera:

main.rs

fn sumar(v1: &Vec<i32>, v2: &Vec<i32>) -> i32
{
	let sum = v1.iter().fold(0i32, |a, &b| a + b);
	let prod = v2.iter().fold(1i32, |a, &b| a * b);
	return sum + prod;
}

fn main() 
{
	let vecuno = vec![2, 3, 5];
	let vecdos = vec![3, 5];
	let rta = sumar(&vecuno, &vecdos);
	println!("{}", vecuno[0]);
	println!("{}", vecdos[0]);
	println!("{}",rta);
}
Anuncios
Anuncios

En este caso no pasamos las variables directamente sino que pasamos sus referencias mediante su operador (&), esto significa que no pasa la propiedad sino que hace un pseudo copy trait donde vincula la copia de la direccion de memoria con la nueva union, por esto en la funcion recibimos los valores de esta forma, esto hace que no debamos devolver todos los valores sino solamente la suma de las dos iteraciones, en el main cambiamos el tuple por una variable y a la hora de pasar los datos volvemos a usar el operador de referencia, por ultimo mostramos todos los datos, compilemos y veamos como es su salida:

tinchicus@dbn001vrt:~/lenguajes/rust/copiar$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `target/debug/copiar`
2
3
25
tinchicus@dbn001vrt:~/lenguajes/rust/copiar$
Anuncios
Anuncios

Como podemos ver quedo un codigo mas simple y facil de entender a comparacion de lo que vimos al post anterior, mientras los valores sean inmutables las referencias no pueden ser cambiadas, esto tiene sentido si lo vemos de la siguiente manera, vamos a suponer que creamos un vector Vec<T> la cual posee ocho valores, cuando realicemos la union este tomara otro tipo en el heap y stack, si nosotros permitimos que este sea modificado nos ocasionara el mismo problema que en otros lenguajes y por lo tanto el compilador no sabra si puede utilizarlo de forma segura o no, por lo tanto para mantener la garantia de que funcione no debemos permitir la modificacion, pero que sucede con los mutables?

Anuncios

Para verlo en accion vamos a crear un nuevo proyecto que llamaremos refmut, una vez creado debemos modificar el codigo generado de main.rs de la siguiente forma:

main.rs

fn main() 
{
	let mut varmut = 5;
	{
		println!("{}", varmut);
		let y = &mut varmut;
		*y += 1;
	}
	println!("{}", varmut);
}
Anuncios

Primero crearemos una variable mutable con un valor, luego tendremos un bloque con dos llaves, en esta primero mostraremos de la variable anteriormente creada, luego crearemos una variable inmutable donde almacenaremos una referencia a la variable mutable creada en primera fase, lo siguiente sera incrementar a esta variable inmutable y por ultimo mostraremos nuevamente el valor de varmut, compilemos y veamos que sucede:

tinchicus@dbn001vrt:~/lenguajes/rust/refmut$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/refmut`
5
6
tinchicus@dbn001vrt:~/lenguajes/rust/refmut$
Anuncios
Anuncios

Como pueden ver funciono perfectamente y no solamente eso sino que «modificamos» a la variable inmutable pero eso es una verdad a medias porque en realidad trabajamos sobre la direccion de memoria de la primera variable no sobre esta, por lo tanto cuando volvemos a llamar a varmut este nos muestra un nuevo valor, este es el concepto de «pedir prestado» la propiedad de la direccion de memoria o la union, en algunas versiones viejas si quitamos las llaves al compilarlo nos devolveria un error porque una referencia no puede ser inmutable y mutable en la misma secuencia, pero en la version que probe esto (1.57.0) no ocurrio funcionando tanto con las llaves como sin ellas, antes de comentar sobre esto vamos a ver dos reglas basicas sobre este tema:

  • Lo que pides prestado (borrow) no debe sobrevivir al original
  • Solo puedes tener una (o mas) referencias de tipo &T (generico) a un recurso o solo una referencia mutable pero no ambas al mismo tiempo
Anuncios
Anuncios

La primera es debido a que no podemos seguir teniendola porque una vez que se vaya del rango sera destruida y si es destruida que seguiras pidiendo prestado?, para el segundo caso se asume que ocurre la Race condition, de la cual hablatrmos mas adelante, porque basicamente se trata evitar que dos referencias accedan al mismo punto de memoria, por esta razon con referencias inmutables podemos tener todas las que queramos pero con las mutables solo podremos tener una referencia valida, para resumir nuestro ultimo codigo podemos decir que mientras logremos finalizar el prestamo antes de utilizarlo nunca tendremos problemas y siempre que no rompamos las dos reglas anteriores.

Anuncios

En resumen, hoy hemos visto a borrowing, que es, como la podemos utilizar, como ya hemos visto anteriormente sin saberlo, tambien hemos visto algunas reglas que debemos tener en cuenta a la hora de trabajar con esto, 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

Donación

Es para mantenimento del sitio, gracias!

$1.50