Día 1: Ejercicios de la Mañana
Arrays y buclesfor
// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ANCHOR: transpose fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] { // ANCHOR_END: transpose let mut result = [[0; 3]; 3]; for i in 0..3 { for j in 0..3 { result[j][i] = matrix[i][j]; } } return result; } // ANCHOR: pretty_print fn pretty_print(matrix: &[[i32; 3]; 3]) { // ANCHOR_END: pretty_print for row in matrix { println!("{row:?}"); } } // ANCHOR: tests #[test] fn test_transpose() { let matrix = [ [101, 102, 103], // [201, 202, 203], [301, 302, 303], ]; let transposed = transpose(matrix); assert_eq!( transposed, [ [101, 201, 301], // [102, 202, 302], [103, 203, 303], ] ); } // ANCHOR_END: tests // ANCHOR: main fn main() { let matrix = [ [101, 102, 103], // <-- the comment makes rustfmt add a newline [201, 202, 203], [301, 302, 303], ]; println!("matrix:"); pretty_print(&matrix); let transposed = transpose(matrix); println!("transposed:"); pretty_print(&transposed); }
Pregunta extra
Requiere conceptos más avanzados. Es posible que parezca que se puede utilizar un slice de slices (&[&[i32]]
) como tipo de entrada para hacer una trasposición y así lograr que nuestra función controle cualquier tamaño de matriz. Sin embargo, esto se viene abajo rápidamente: el tipo de resultado devuelto no puede ser &[&[i32]]
, ya que necesita ser el propietario de los datos que devuelve.
Puedes probar a utilizar algo como Vec<Vec<i32>>
, pero esto tampoco funciona desde el principio: es difícil cambiar de Vec<Vec<i32>>
a &[&[i32]]
, por lo que tampoco puedes usar pretty_print
de forma sencilla.
Una vez que veamos los traits y los genéricos, podremos usar el trait std::convert::AsRef
para abstraer cualquier elemento que se pueda referenciar, como un slice.
use std::convert::AsRef; use std::fmt::Debug; fn pretty_print<T, Line, Matrix>(matrix: Matrix) where T: Debug, // A line references a slice of items Line: AsRef<[T]>, // A matrix references a slice of lines Matrix: AsRef<[Line]> { for row in matrix.as_ref() { println!("{:?}", row.as_ref()); } } fn main() { // &[&[i32]] pretty_print(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]); // [[&str; 2]; 2] pretty_print([["a", "b"], ["c", "d"]]); // Vec<Vec<i32>> pretty_print(vec![vec![1, 2], vec![3, 4]]); }
Además, el propio tipo no requeriría que los slices secundarios fueran de la misma longitud, por lo que dicha variable podría contener una matriz no válida.