Valores opcionales
En los ejemplos con los bucles while ya vimos esta sintaxis:
const nombre: ?tipo;
Un signo de interrogación ? antes del tipo de dato índica que se trata de un valor optional - es decir, un valor potencialmente nulo.
Podemos convertir cualquier tipo de valor en opcional poniendo este signo de interrogación por delante. Tal y como lo hacemos en este caso:
|
n_efficiency_per_meter: ?f32, // valor opcional |
Usamos la expresión orelse para asignar un valor determinado cuando nos encontramos con null.
|
self.n_efficiency_per_meter orelse HydroTower.N_EFFICIENCY_PER_METER, |
Combinar los valores opcionales y la expresión orelse nos permite definir valores por defecto para los parámetros:
|
const o_tower = HydroTower{ .n_height = 4.5, // en la eficiencia no ponemos nada específico -> valor opcional .n_efficiency_per_meter = null, }; |
El camino que debía recorrer el agua desde un pequeño azud en el río hasta el castillo, para desgracia del ingeniero, no era una línea recta. El inventor, tras muchos cálculos, pruebas y ajustes, valiéndose de sus conocimientos - logró componer el sistema con una serie de torres. Estas funcionaban únicamente con la fuerza del propio agua.
Fue un trabajo muy complicado ya que cualquier incremento en la pérdida de agua en una torre afectaba todo el sistema. Por suerte, el inventor tenía experiencia previa en maquinaría de precisión ya que había sido relojero del rey.
hydrotower_system.zig |
|
const std = @import("std"); const print = std.debug.print; const ArrayList = std.ArrayList; // una torre con cazos oscilantes const HydroTower = struct { const N_EFFICIENCY_PER_METER: f32 = 0.98; n_height: f32, fn lift_water(self: *const HydroTower, n_input: ?f32) struct { f32, f32 } { return .{ (n_input orelse 0) * std.math.pow( f32, HydroTower.N_EFFICIENCY_PER_METER, self.n_height, ), self.n_height, }; } // simulamos una altura de torre construida entre 3.5 y 5m fn get_height_btw(n_min: f32, n_max: f32) f32 { return round2(get_rand(n_min, n_max)); } }; // caudal del río llevado hasta la torre const WaterFlow = struct { n_liters_per_second: f32, fn get_fps(self: *const WaterFlow) f32 { const n_min = self.n_liters_per_second * 0.90; return round2(get_rand(n_min, self.n_liters_per_second)); } }; // función inline para redondear a 2 decimales inline fn round2(n_x: f32) f32 { return @floor(100 * n_x) / 100; } // función inline para obtener un núm random entre n_min y n_max inline fn get_rand(n_min: f32, n_max: f32) f32 { return std.Random.float(std.crypto.random, f32) * (n_max - n_min) + n_min; } pub fn main() !void { print("~~~~~\n", .{}); // caudal 2L por segundo const o_river = WaterFlow{ .n_liters_per_second = 2 }; var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const o_alloc = gpa.allocator(); // inicializamos las torres var a_towers:ArrayList(HydroTower) = .empty; defer a_towers.deinit(o_alloc); // innecesario en el main const n_castle_at: f32 = 90; var n_total_height: f32 = 0; var n_i: usize = 0; while (n_total_height < n_castle_at) : (n_i += 1) { // dependiendo del terreno la altura oscilará const n_tower_height = HydroTower.get_height_btw(3.0, 5.0); n_total_height += n_tower_height; const o_tower = HydroTower{ .n_height = n_tower_height, }; // añadimos una torre a la lista try a_towers.append(o_alloc, o_tower); } print("Se han construido: {} torres\n", .{a_towers.items.len}); var n_riverflow: f32 = o_river.get_fps(); var n_total_h: f32 = 0; for (a_towers.items, 0..) |o_tower, n_ix| { n_riverflow, const n_ht = o_tower.lift_water(n_riverflow); n_total_h += n_ht; print("{}: {}L a {}m\n", .{ n_ix + 1, round2(n_riverflow), round2(n_total_h) }); } } |
|
$ zig run hydrotower_system.zig |
|
~~~~~ Se han construido: 21 torres 1: 1.7L a 3.48m ... 21: 0.29L a 90.18m |