Lección 20 · 20 de 20
Proyecto: carrito de la compra · Dart
Un proyecto en Dart que reúne el curso: un carrito de la compra con mapas, funciones, excepciones, null safety, fold y una expresión switch para el descuento.

Este programa junta lo aprendido en el curso. Los precios de la tienda están en un mapa `const` fuera de main, porque no cambian. El carrito es una lista de líneas producto,unidades, tal como llegarían de un formulario o de un archivo, y tres de ellas tienen errores a propósito.
La función lineCost calcula el coste de una línea. split(',') separa el producto de las unidades; prices[parts[0]] da un double?, porque el producto puede no existir, e int.tryParse da un int?, porque el texto puede no ser un número. Si falta alguno de los dos, o la cantidad no es positiva, `throw` lanza un ArgumentError con un mensaje claro; si no, devuelve precio por unidades. Tras esos if, Dart sabe que ninguno es null.
En main, el bucle suma el coste de cada línea en el mapa totals con (totals[product] ?? 0) + ..., de modo que la leche, que aparece dos veces, se acumula. El `try` con `on ArgumentError catch (e)` atiende las líneas incorrectas: se escriben con Skipped: y el carrito sigue.
Para el tique, forEach escribe cada producto con la función de flecha row, que alinea las columnas con padRight y padLeft. `fold` suma los valores del mapa y una expresión `switch` con patrones >= 20 y >= 10 elige el descuento: con 17,60 euros toca un 5 %, y el total queda en 16.72.
Un buen siguiente paso es darle una pantalla: en DMarlon Studio puede diseñar en el lienzo de teléfono una aplicación Flutter con la lista de productos y un botón de pagar, y reutilizar estas mismas funciones de Dart.
Código · main.dart
const prices = {'bread': 1.20, 'milk': 0.95, 'cheese': 4.50, 'apples': 2.30};// Gives the cost of one "product,units" line, or throws an error.double lineCost(String line) { var parts = line.split(','); double? price = prices[parts[0]]; int? units = int.tryParse(parts[1]); if (price == null) throw ArgumentError('${parts[0]} is not sold here'); if (units == null || units <= 0) throw ArgumentError('bad quantity in "$line"'); return price * units;}String row(String label, double euros) => label.padRight(14) + euros.toStringAsFixed(2).padLeft(7);void main() { var cart = ['bread,2', 'cheese,1', 'milk,x', 'apples,3', 'ham,1', 'milk,4', 'bread,0']; var totals = <String, double>{}; for (var line in cart) { var product = line.split(',')[0]; try { totals[product] = (totals[product] ?? 0) + lineCost(line); } on ArgumentError catch (e) { print('Skipped: ${e.message}'); } } totals.forEach((product, cost) => print(row(product, cost))); double subtotal = totals.values.fold(0, (a, b) => a + b); double rate = switch (subtotal) { >= 20 => 0.10, >= 10 => 0.05, _ => 0.0 }; print('-' * 21); print(row('Subtotal', subtotal)); print(row('Discount (${(rate * 100).round()}%)', -subtotal * rate)); print(row('TOTAL', subtotal * (1 - rate)));}Salida · dart run main.dart
Skipped: bad quantity in "milk,x" Skipped: ham is not sold here Skipped: bad quantity in "bread,0" bread 2.40 cheese 4.50 apples 6.90 milk 3.80 --------------------- Subtotal 17.60 Discount (5%) -0.88 TOTAL 16.72
Para recordar
- Los datos fijos van en un
constfuera demain. double?eint?obligan a pensar en lo que puede faltar.throwen la función ytryen el bucle separan el error de su tratamiento.foldsuma los valores de un mapa.- Una expresión
switchconvierte el subtotal en un descuento.
Ejercicio
Añada un mapa con el IVA de cada producto (4 para el pan y la leche, 10 para el resto) y escriba en el tique una línea VAT con el impuesto incluido en el total.