Translate

jueves, 5 de octubre de 2023

Generics en Rust


Rust soporta genéricos, lo que le permite abstraer algoritmos o estructuras de datos (como ordenamiento o un árbol binario) sobre los tipos definidos por nosotros o por el sdk.

Puede utilizar genéricos para abstraer el tipo de campo concreto:

#[derive(Debug)]

struct Point<T> {

    x: T,

    y: T,

}


fn main() {

    let integer = Point { x: 5, y: 10 };

    let float = Point { x: 1.0, y: 4.0 };

    println!("{integer:?} and {float:?}");

}


Lo hermoso es que infiere el tipo dependiendo de como lo usamos. Es decir, si hacemos : 


let x = Point { x: 5, y: 10.0 };


no va a compilar. 


Se puedes declarar un tipo genérico en tu bloque impl:


#[derive(Debug)]

struct Point<T>(T, T);


impl<T> Point<T> {

    fn x(&self) -> &T {

        &self.0  // + 10

    }


    // fn set_x(&mut self, x: T)

}


fn main() {

    let p = Point(5, 10);

    println!("p.x = {}", p.x());

}


¿Por qué T se especifica dos veces en impl<T> Point<T> {}? ¿No es eso redundante?

Esto se debe a que es una sección de implementación genérica para tipos genéricos. Son genéricos independientemente. Significa que estos métodos están definidos para cualquier T.

Es posible escribir impl Point<u32> { .. }.

Point sigue siendo genérico y puedes usar Point<f64>, pero los métodos de este bloque solo estarán disponibles para Point<u32>.

miércoles, 4 de octubre de 2023

Agregando Swagger a nuestro proyecto Echo


Luego de crear nuestro proyecto con echo, vamos a agregar swagger

Empezamos agregando la librería de swag 


go get -d github.com/swaggo/swag/cmd/swag

go install github.com/swaggo/swag/cmd/swag@latest


Luego ejecutamos Swag en la carpeta raíz del proyecto Go que contiene el archivo main.go, Swag analizará los comentarios y generará los archivos necesarios (carpeta docs y docs/doc.go).


swag init


y luego agregamos echo para swagger


go get -u github.com/swaggo/echo-swagger


Y ahora tenemos swagger en nustro proyecto echo : 


package main


import (

"github.com/labstack/echo/v4"

"github.com/swaggo/echo-swagger"


_ "github.com/swaggo/echo-swagger/example/docs" // docs is generated by Swag CLI, you have to import it.

)


// @title Swagger Example API

// @version 1.0

// @description This is a sample server Petstore server.

// @termsOfService http://swagger.io/terms/


// @contact.name API Support

// @contact.url http://www.swagger.io/support

// @contact.email support@swagger.io


// @license.name Apache 2.0

// @license.url http://www.apache.org/licenses/LICENSE-2.0.html


// @host petstore.swagger.io

// @BasePath /v2

func main() {

e := echo.New()


e.GET("/swagger/*", echoSwagger.WrapHandler)


e.Logger.Fatal(e.Start(":1323"))

}


En mi caso solo tengo que agregar : 

el import : 

import (_ "myapp/docs")

y el router : 

e.GET("/swagger/*", echoSwagger.WrapHandler)

y tengo estos 2 servicios con su documentación  : 

// HealthCheck godoc
// @Summary Show the status of server.
// @Description get the status of server.
// @Tags root
// @Accept */*
// @Produce json
// @Success 200 {object} map[string]interface{}
// @Router /health/check [get]
func HealthCheck(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]interface{}{
"data": "Server is up and running",
})
}

// Info godoc
// @Summary Show the info of server.
// @Description get the info of server.
// @Tags root
// @Accept */*
// @Produce json
// @Success 200 {object} computer.SysInfo
// @Router /health/info [get]
func Info(c echo.Context) error {
return c.JSON(http.StatusOK, computer.Info())
}

Y se genero el siguiente swagger.json :

{
    "swagger": "2.0",
    "info": {
        "contact": {}
    },
    "paths": {
        "/health/check": {
            "get": {
                "description": "get the status of server.",
                "consumes": [
                    "*/*"
                ],
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "root"
                ],
                "summary": "Show the status of server.",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/health/info": {
            "get": {
                "description": "get the info of server.",
                "consumes": [
                    "*/*"
                ],
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "root"
                ],
                "summary": "Show the info of server.",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/computer.SysInfo"
                        }
                    }
                }
            }
        }
    },
    "definitions": {
        "computer.SysInfo": {
            "type": "object",
            "properties": {
                "disk": {
                    "type": "integer"
                },
                "hostname": {
                    "type": "string"
                },
                "platform": {
                    "type": "string"
                },
                "ram": {
                    "type": "integer"
                },
                "ram available": {
                    "type": "integer"
                },
                "ram free": {
                    "type": "integer"
                },
                "uptime": {
                    "type": "integer"
                }
            }
        }
    }
}

Dejo link : https://github.com/swaggo/echo-swagger

martes, 3 de octubre de 2023

Módulos en Rust y su Ubicación


Rust es conocido por su sistema de módulos sólido y su capacidad para administrar y organizar el código de manera efectiva. Los módulos permiten dividir un proyecto en partes más pequeñas y lógicas, facilitando el mantenimiento y la colaboración.

Los módulos en Rust son unidades de organización para el código que ayudan a dividir una aplicación en partes más pequeñas y manejables. Estos módulos permiten agrupar funciones, tipos, estructuras y otros elementos relacionados de manera lógica.

Para definir un módulo en Rust, utilizamos la palabra clave mod. Por ejemplo:

// Definición de un módulo llamado 'my_module'

mod my_module {

    // Contenido del módulo aquí

}

En Rust, la ubicación de los módulos dentro de un proyecto es importante para su visibilidad y accesibilidad desde otros módulos. 

Omitir mod le indicará a Rust que lo busque en otro archivo, si escribimos:

mod garden;

Esto le indica a Rust que el contenido del módulo garden se encuentra en src/garden.rs. De manera similar, se puede encontrar un módulo garden::vegetables en src/garden/vegetables.rs.

La el directorio raíz está en:

  • src/lib.rs (para una libreria)
  • src/main.rs (para una aplicación binaria)
Los módulos definidos en archivos también se pueden documentar mediante "comentarios internos del documento". Estos documentan el elemento que los contiene (en este caso, un módulo).

//! This module implements the garden, including a highly performant germination
//! implementation.

// Re-export types from this module.
pub use seeds::SeedPacket;
pub use garden::Garden;

/// Sow the given seed packets.
pub fn sow(seeds: Vec<SeedPacket>) { todo!() }

/// Harvest the produce in the garden that is ready.
pub fn harvest(garden: &mut Garden) { todo!() }


Antes de Rust 2018, los módulos debían estar ubicados en module/mod.rs en lugar de module.rs, y esta sigue siendo una alternativa funcional para las ediciones posteriores a 2018.

La razón principal para introducir filename.rs como alternativa a filename/mod.rs fue porque muchos archivos llamados mod.rs pueden ser difíciles de distinguir en los IDE.

Un anidamiento más profundo puede utilizar carpetas, incluso si el módulo principal es un archivo:

src/
├── main.rs
├── top_module.rs
└── top_module/
    └── sub_module.rs

El lugar donde Rust buscará los módulos se puede cambiar con una directiva del compilador:

#[path = "some/path.rs"]
mod some_module;

Esto es útil, por ejemplo, si desea colocar pruebas para un módulo en un archivo llamado some_module_test.rs, similar a la convención en Go.


Paths en Rust




Los Paths se resuelven de la siguiente manera:

  • Como ruta relativa:
    • foo o self::foo se refiere a foo en el módulo actual,
    • super::foo se refiere a foo en el módulo principal.
  • Como Path absoluto:
    • crate::foo se refiere a foo en la raíz del modulo actual,
    • bar::foo se refiere a foo en el modulo de bar. 

Un módulo puede incorporar símbolos de otro módulo al alcance con su uso. Normalmente verá algo como esto en la parte superior de cada módulo:

use std::collections::HashSet;

use std::mem::transmute;

lunes, 2 de octubre de 2023

Crear un proyecto en Go y Echo


Vamos a crear un proyecto con echo y go. Echo es un framework web minimalista y de alto rendimiento para Go. Está diseñado para ser simple y eficiente, lo que lo hace adecuado para el desarrollo rápido de API REST. Echo es especialmente apreciado por su rendimiento y facilidad de uso.


$ mkdir myapp && cd myapp

$ go mod init myapp

$ go get github.com/labstack/echo/v4

$ go get github.com/labstack/echo/v4/middleware


Con esto, hemos importado las librerías necesarias si miramos el archivo go.mod : 


module myapp 


go 1.19


require (

github.com/golang-jwt/jwt v3.2.2+incompatible // indirect

github.com/labstack/echo/v4 v4.11.1 // indirect

github.com/labstack/gommon v0.4.0 // indirect

github.com/mattn/go-colorable v0.1.13 // indirect

github.com/mattn/go-isatty v0.0.19 // indirect

github.com/valyala/bytebufferpool v1.0.0 // indirect

github.com/valyala/fasttemplate v1.2.2 // indirect

golang.org/x/crypto v0.11.0 // indirect

golang.org/x/net v0.12.0 // indirect

golang.org/x/sys v0.10.0 // indirect

golang.org/x/text v0.11.0 // indirect

golang.org/x/time v0.3.0 // indirect

)


Ahora vamos a hacer un pequeño programa que tenga un hola mundo : 


import (

  "github.com/labstack/echo/v4"

  "github.com/labstack/echo/v4/middleware"

  "net/http"

)


func main() {

  // Echo instance

  e := echo.New()


  // Middleware

  e.Use(middleware.Logger())

  e.Use(middleware.Recover())


  // Routes

  e.GET("/", hello)


  // Start server

  e.Logger.Fatal(e.Start(":1323"))

}


// Handler

func hello(c echo.Context) error {

  return c.String(http.StatusOK, "Hola Mundo!")

}


Y Listo!!


Dejo links: 

https://echo.labstack.com/docs

https://github.com/labstack/echo

domingo, 1 de octubre de 2023

Zig: Un Lenguaje de Programación Moderno y Seguro


Zig es un lenguaje de programación diseñado para ofrecer una combinación de alto rendimiento, seguridad y facilidad de uso. A diferencia de muchos otros lenguajes, Zig se centra en proporcionar un control más preciso sobre el hardware y una sintaxis clara y legible. Y permite interacción con C o C++

Una de las características más notables de Zig es su enfoque en la "compilación asegurada". Esto significa que Zig se esfuerza por evitar comportamientos indefinidos en tiempo de ejecución y errores comunes en tiempo de compilación. El compilador de Zig es riguroso en la detección de errores y problemas de seguridad, lo que facilita la creación de software más confiable y seguro desde el principio.

Zig se enorgullece de su sintaxis clara y legible, lo que facilita la lectura y escritura de código. La intención del código es evidente, lo que ayuda a reducir la posibilidad de errores y facilita la colaboración entre equipos de desarrollo. Veamos un ejemplo : 


const std = @import("std");


pub fn main() void {

    const stdout = std.io.getStdOut().writer();

    try stdout.print("¡Hola, mundo!\n");

}


A pesar de su sintaxis amigable, Zig brinda un control preciso sobre el hardware y el sistema operativo. Esto lo hace adecuado para programación de sistemas, desarrollo de controladores, y otras tareas de bajo nivel.

Zig es compatible con diversas plataformas, incluidas Windows, macOS, Linux y más. Esto permite a los desarrolladores escribir código una vez y ejecutarlo en múltiples sistemas operativos sin modificarlo significativamente.

Zig es un lenguaje de programación moderno y seguro que combina la facilidad de uso con un alto nivel de control y rendimiento. Si estás interesado en la creación de software confiable y eficiente, Zig podría ser una excelente opción para explorar.


Dejo link : https://ziglang.org/

Nombres en Go


Los nombres son tan importantes en Go como en cualquier otro Lenguaje. Incluso tienen un efecto semántico: la visibilidad de un nombre fuera de un paquete está determinada por si su primer carácter está en mayúscula. Por lo tanto, vale la pena dedicar un poco de tiempo a hablar sobre las convenciones de nomenclatura en los programas Go.

Nombres de paquetes: Cuando se importa un paquete, el nombre del paquete se convierte en un descriptor de acceso para el contenido. Después de


import "bytes"


el paquete que importa puede usar bytes.Buffer. Es útil si todos los que usan el paquete pueden usar el mismo nombre para referirse a su contenido, lo que implica que el nombre del paquete debe ser bueno: breve, conciso y evocador. Por convención, los paquetes reciben nombres de una sola palabra en minúsculas; no debería haber necesidad de guiones bajos ni mayúsculas mixtas. Peque por el lado de la brevedad, ya que todos los que usen su paquete escribirán ese nombre. Y no te preocupes por las colisiones a priori. El nombre del paquete es sólo el nombre predeterminado para las importaciones; No es necesario que sea único en todo el código fuente y, en el raro caso de una colisión, el paquete importado puede elegir un nombre diferente para usarlo localmente. En cualquier caso, la confusión es rara porque el nombre del archivo en la importación determina exactamente qué paquete se está utilizando.

Otra convención es que el nombre del paquete es el nombre base de su directorio fuente; el paquete en src/encoding/base64 se importa como "encoding/base64" pero tiene el nombre base64, no encoding_base64 ni encodingBase64.

El importador de un paquete usará el nombre para referirse a su contenido, por lo que los nombres exportados en el paquete pueden usar ese hecho para evitar repeticiones. (No utilice la notación import ., que puede simplificar las pruebas que deben ejecutarse fuera del paquete que están probando, pero que de lo contrario debe evitarse). Por ejemplo, el tipo Reader en el paquete bufio se llama Reader, no BufReader, porque los usuarios lo ven como bufio.Reader, que es un nombre claro y conciso. Además, debido a que las entidades importadas siempre se abordan con el nombre de su paquete, bufio.Reader no entra en conflicto con io.Reader. De manera similar, la función para crear nuevas instancias de ring.Ring, que es la definición de un constructor en Go, normalmente se llamaría NewRing, pero dado que Ring es el único tipo exportado por el paquete, y dado que el paquete se llama ring, es llamado simplemente New, que los clientes del paquete ven como ring.New. En conclusión, se debe de utilizar la estructura del paquete para ayudarle a elegir buenos nombres.

Otro ejemplo breve es once.Do; once.Do(setup) se lee bien y no mejoraría si se escribiera once.DoOrWaitUntilDone(setup). Los nombres largos no hacen que las cosas sean más legibles automáticamente. Un comentario útil sobre un documento a menudo puede ser más valioso que un nombre muy largo.

Getters: Go no proporciona soporte automático para getters y setters. No hay nada de malo en proporcionar getters y setters usted mismo, y a menudo es apropiado hacerlo, pero no es idiomático ni necesario poner Get en el nombre del getter. Si tiene un campo llamado owner, el método getter debe llamarse Owner, no GetOwner. El uso de nombres en mayúsculas para la exportación proporciona el gancho para discriminar el campo del método. Una función de set, si es necesaria, probablemente se llamará SetOwner. Ambos nombres se leen bien en la práctica:


owner := obj.Owner()

if owner != user {

    obj.SetOwner(user)

}

Nombres de interfaz: Por convención, las interfaces de un método se denominan mediante el nombre del método más un sufijo -er o una modificación similar para construir un sustantivo de agente: Reader, Writer, Formatter, CloseNotifier, etc.

Para evitar confusiones, no le dé a su método uno de esos nombres a menos que tenga la misma firma y significado. Por el contrario, si su tipo implementa un método con el mismo significado que un método de un tipo conocido, asígnele el mismo nombre y firma; por ejemplo llame a su método convertidor a string String, no ToString.

MixedCaps: la convención en Go es usar MixedCaps en lugar de guiones bajos para escribir nombres de varias palabras.


Comentarios en Go


Go proporciona comentarios de bloque /* */ estilo C y comentarios de línea // estilo C++. Los comentarios de línea son la norma; Los comentarios de bloque aparecen principalmente como comentarios de paquete, pero son útiles dentro de una expresión o para deshabilitar grandes extensiones de código.

Se considera que los comentarios que aparecen antes de las declaraciones de nivel superior, sin nuevas líneas intermedias, documentan la declaración misma. Estos "comentarios de documentos" son la documentación principal de un paquete o comando de Go determinado. 

Los “comentarios de documentos” son comentarios que aparecen inmediatamente antes de las declaraciones de paquete, const, func, type y var de nivel superior sin nuevas líneas intermedias. Cada nombre exportado (en mayúscula) debe tener un comentario de documento.

Los paquetes go/doc y go/doc/comment brindan la capacidad de extraer documentación del código fuente de Go, y una variedad de herramientas utilizan esta funcionalidad. El comando go doc busca e imprime el comentario del documento para un paquete o símbolo determinado. (Un símbolo es una constante, función, tipo o var de nivel superior). El servidor web pkg.go.dev muestra la documentación para los paquetes públicos de Go (cuando sus licencias permiten ese uso). El programa que sirve a ese sitio es golang.org/x/pkgsite/cmd/pkgsite, que también se puede ejecutar localmente para ver la documentación de módulos privados o sin conexión a Internet. El servidor de idiomas gopls proporciona documentación al editar archivos fuente de Go en IDE.

Por ejemplo, Cada paquete debe tener un comentario que lo presente. Proporciona información relevante para el paquete en su conjunto y, en general, establece expectativas para el paquete. Especialmente en paquetes grandes, puede resultar útil que el comentario del paquete brinde una breve descripción general de las partes más importantes de la API, vinculando a otros comentarios de documentos según sea necesario.

Si el paquete es simple, el comentario del paquete puede ser breve. Por ejemplo:


// Package path implements utility routines for manipulating slash-separated

// paths.

//

// The path package should only be used for paths separated by forward

// slashes, such as the paths in URLs. This package does not deal with

// Windows paths with drive letters or backslashes; to manipulate

// operating system paths, use the [path/filepath] package.

package path


Los corchetes en [ruta/ruta de archivo] crean un enlace de documentación.

Como se puede ver en este ejemplo, los comentarios de Go doc utilizan oraciones completas. Para un comentario de paquete, eso significa que la primera oración comienza con "Package".

Dejo link: https://go.dev/doc/comment



Visibilidad entre modulos en Rust


En Rust podemos definir la visibilidad de los métodos por medio de los modulos. 

Los elementos del módulo son privados de forma predeterminada (oculta los detalles de implementación).

Los elementos de padres y hermanos siempre están visibles.

En otras palabras, si un elemento es visible en el módulo foo, será visible en todos los descendientes de foo.


mod outer {

    fn private() {

        println!("outer::private");

    }


    pub fn public() {

        println!("outer::public");

    }


    mod inner {

        fn private() {

            println!("outer::inner::private");

        }


        pub fn public() {

            println!("outer::inner::public");

            super::private();

        }

    }

}


fn main() {

    outer::public();

}


Utilice la palabra clave pub para hacer públicos los medotos de los módulos.

Además, existen especificadores pub(...) avanzados para restringir el alcance de la visibilidad pública.

Configurar la visibilidad como pub(crate) es un patrón común.

Con menos frecuencia, puedes dar visibilidad a una ruta específica.

En cualquier caso, se debe otorgar visibilidad a un módulo ancestro (y a todos sus descendientes).


Dejo link: https://doc.rust-lang.org/reference/visibility-and-privacy.html#pubin-path-pubcrate-pubsuper-and-pubself

miércoles, 27 de septiembre de 2023

Libros gratuitos

 Me llegaron ests libros de web code geeks :

Get Schooled By Web Code Geeks

Download FREE IT Guides!

 

Starting with Kotlin Cheatsheet

Welcome to the Kotlin Cheatsheet! This document aims to provide you with a quick reference guide to Kotlin programming language. Whether you are a beginner getting started with Kotlin or...

 
 

Querying Graphs with Neo4j Cheatsheet

This cheatsheet is your guide to effectively querying graphs using Neo4j. Whether you’re a seasoned database professional looking to expand your skills or a curious enthusiast eager to...

 
 

Getting Started with GraphQL Cheatsheet

In this cheatsheet, we will embark on a journey to explore the core principles of GraphQL and its ecosystem. We'll cover topics such as schema design, querying and mutation operations,...

 
 

Starting with Windows PowerShell Cheatsheet

This cheatsheet provides an overview of the most commonly used PowerShell commands, grouped by category. Whether you’re new to PowerShell or an experienced user, this cheatsheet will...

 
 

Core Python Cheatsheet

This cheatsheet is intended to serve as a quick reference guide for Python programming. It covers some of the most commonly used syntax and features of the language, including data types,...

 
 

Starting with Docker Cheatsheet

This guide aims to provide an overview of the key concepts and features of Docker, along with practical examples and tips for using it effectively. It covers topics such as Docker...

 

martes, 26 de septiembre de 2023

Explorando la Programación Funcional en Scala


Los quiero invitar a una charla que voy a dar para scaLatin, sobre programación funcional. 

Exploraremos el mundo de la programación funcional en Scala a través de escenarios concretos de resolución de problemas. Nos sumergiremos en la elegancia de las funciones lambda y aprenderemos cómo crearlas y aplicarlas para optimizar nuestro código.

Luego aplicaremos pattern matching y descubriremos cómo simplifica el manejo de datos complejos y mejora la legibilidad del código.

A lo largo de nuestro viaje, aprovecharemos el poder de la recursividad para resolver problemas de manera eficiente y demostraremos cómo las mónadas pueden ayudarnos a controlar la complejidad de nuestros programas.

Ya sea que sea nuevo en estos conceptos o busque conocimientos avanzados, esta sesión promete equiparlo con habilidades prácticas y una comprensión más profunda de la programación funcional en Scala.

Dejo links: 

https://www.linkedin.com/events/7112416236554137600/

https://www.meetup.com/scalatin/events/296351847/

lunes, 25 de septiembre de 2023

gofmt de Go


Las cuestiones de formato son las más polémicas pero las menos trascendentes. Las personas pueden adaptarse a diferentes estilos de formato, pero es mejor si no es necesario y se dedica menos tiempo al tema si todos siguen el mismo estilo. El problema es cómo abordar esta utopía sin una larga guía de estilo prescriptiva.

Con Go adoptaron un enfoque inusual y dejaron que la máquina se encargue de la mayoría de los problemas de formato. El programa gofmt (también disponible como go fmt, que opera a nivel de paquete en lugar de a nivel de archivo fuente) lee un programa Go y emite el código fuente en un estilo estándar de sangría y alineación vertical, reteniendo y, si es necesario, reformateando los comentarios. Si desea saber cómo manejar alguna situación de diseño nueva, ejecute gofmt; Si la respuesta no parece correcta, reorganice su programa (o registre un error sobre gofmt), no lo solucione.

Por ejemplo, no es necesario perder tiempo alineando los comentarios en los campos de una estructura. Gofmt lo hará. Dada la declaración


type T struct {

    name string // name of the object

    value int // its value

}


gofmt alineará las columnas:


type T struct {

    name    string // name of the object

    value   int    // its value

}


Todo el código Go en los paquetes estándar ha sido formateado con gofmt.


Quedan algunos detalles de formato:


Sangría: Se usa tabs para la sangría y gofmt las emite de forma predeterminada. Utilice espacios sólo si es necesario.

Longitud de la línea: Go no tiene límite de longitud de línea. Si una línea parece demasiado larga, envuélvala y sangra con una tab adicional.

Paréntesis: Go necesita menos paréntesis que C y Java: las estructuras de control (if, for, switch) no tienen paréntesis en su sintaxis. Además, la jerarquía de precedencia de operadores es más corta y clara, por lo que

x<<8 + y<<16

significa lo que implica el espacio, a diferencia de los otros lenguajes.

Juego de Serie en Clojure


Cuando quiero aprender un nuevo lenguaje desarrollo un juego de series, es decir aparece una serie con un valor faltante y el jugador debe completarlo.

Uno de los requerimientos no funcionales es que se pueda agregar una serie nueva fácilmente.

Vamos a desarrollar este juego en Clojure:

Empecemos desarrollo de la serie, la serie tiene como responsabilidad generarse y si lo hacemos de esta manera podemos utilizar la potencia del polimorfismo, para que no quede acoplado la generación de la serie con el desarrollo del juego:

(ns secuencia-clojure.core

  (:gen-class))


(import '(java.util Scanner))

(def scan (Scanner. *in*))


   

(defn generateSecEven []

  (def seed (rand-int 30))

  (for [x (range seed (+ seed 4))] (* x 2))

)

   

(defn generateSecOdd []

  (def seed (rand-int 30))

  (for [x (range seed (+ seed 4))] (+ (* x 2) 1))

)


(defn generateSecFibo []

  (def seed (rand-int 30))

  (def seed2 (* seed 2))

  (def seed3 (* seed 3))

  (list seed seed seed2 seed3)

)

Y listo!! ahora en el main tenemos que llamar a esta función y ver si esta bien el resultado: 



(defn generateSec []
  (def seed (rand-int 3))
  (cond 
    (= seed 0) (generateSecEven)
    (= seed 1) (generateSecOdd)
    (= seed 2) (generateSecFibo)   
  )
)

(defn printSec [sec]
  (print (nth sec 0))
  (print " ")
  (print (nth sec 1))
  (print " ")
  (print " __ ")
  (print " ")
  (println (nth sec 3))
)

(defn game
  [points]
  (def sec (generateSec))
  (def sol (nth sec 2))
  
  (printSec sec)
  
  (let [data (read-line)]
  (if (= data (str sol))
    (do 
      (println "Correct!! the point is " (str (+ points 1)))
      (game (+ points 1))
    )
    (do 
      (println "Wrong!! the point is " (str (- points 1)))
      (game (- points 1))
    )))
)


(defn -main
  [& args]
  (game 0))

Y eso es todo a jugar se a dicho!!

Dejo el repositorio git: 

viernes, 22 de septiembre de 2023

Módulos en Rust


Hemos visto cómo los bloques impl nos permiten asignar funciones de espacio de nombres a un tipo.

De manera similar, mod nos permite tipos de espacios de nombres y funciones:

mod foo {

    pub fn do_something() {

        println!("In the foo module");

    }

}


mod bar {

    pub fn do_something() {

        println!("In the bar module");

    }

}


fn main() {

    foo::do_something();

    bar::do_something();

}

Los paquetes brindan funcionalidad e incluyen un archivo Cargo.toml que describe cómo crear un paquete de más de 1 caja.

Las cajas son un árbol de módulos, donde una caja binaria crea un ejecutable y una caja de biblioteca se compila en una biblioteca.

Los módulos definen la organización y alcance.


martes, 19 de septiembre de 2023

Cell y RefCell en Rust


Cell y RefCell implementan lo que Rust llama mutabilidad interior: mutación de valores en un contexto inmutable.

La celda se usa normalmente para tipos simples, ya que requiere copiar o mover valores. Los tipos de interiores más complejos suelen utilizar RefCell, que rastrea referencias compartidas y exclusivas en tiempo de ejecución y entra en pánico si se utilizan incorrectamente.


use std::cell::RefCell;

use std::rc::Rc;


#[derive(Debug, Default)]

struct Node {

    value: i64,

    children: Vec<Rc<RefCell<Node>>>,

}


impl Node {

    fn new(value: i64) -> Rc<RefCell<Node>> {

        Rc::new(RefCell::new(Node { value, ..Node::default() }))

    }


    fn sum(&self) -> i64 {

        self.value + self.children.iter().map(|c| c.borrow().sum()).sum::<i64>()

    }

}


fn main() {

    let root = Node::new(1);

    root.borrow_mut().children.push(Node::new(5));

    let subtree = Node::new(10);

    subtree.borrow_mut().children.push(Node::new(11));

    subtree.borrow_mut().children.push(Node::new(12));

    root.borrow_mut().children.push(subtree);


    println!("graph: {root:#?}");

    println!("graph sum: {}", root.borrow().sum());

}


Si estuviéramos usando Cell en lugar de RefCell en este ejemplo, tendríamos que sacar el Nodo de Rc para empujar a los elementos secundarios y luego volver a colocarlo. Esto es seguro porque siempre hay un valor sin referencia en la celda, pero no es ergonómico.

Para hacer cualquier cosa con un Nodo, debe llamar a un método RefCell, generalmente borrow o borrow_mut.