Mientrascompletamente al azar no es realmente posible, todavía podemos tener números pseudoaleatorios en las computadoras.
Podemos tenerregularnúmeros pseudoaleatorios, ycriprográficamente seguronúmeros pseudoaleatorios.
Veamos cómo hacerlo en Go.
Números pseudoaleatorios
losmath/rand
paqueteproporcionada por Go Standard Library nos brindageneradores de números pseudoaleatorios (PRNG), también llamadogeneradores de bits aleatorios deterministas.
Al igual que con todos los generadores de pseudo números, cualquier número generado a través demath/rand
esno es realmente aleatoriopor defecto, como deterministasiempre imprimirá el mismo valor cada vez.
Como ejemplo, intente ejecutar este código que introducerand.Intn(n)
, que devuelve un número aleatorio entre0
yn - 1
.
package main
import (
“fmt”
“math/rand”
)
func main() {
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
}
Siempre verá la misma secuencia cada vez que ejecute el programa. El número aleatorio cambia dentro del programa, pero cada vez que lo ejecuta, obtendrá el mismo resultado:
11
27
17
29
1
Esto se debe a que, por defecto, la semilla es siempre la misma, el número1
. Para obtener un número aleatorio, debe proporcionar un únicosemillapara su programa. Realmente desea no olvidar la siembra y, en su lugar, siembre correctamente nuestro generador de pseudonumber. ¿Cómo?
Usarrand.Seed()
antes de llamar a cualquiermath/rand
método, pasando unint64
valor. Solo necesita sembrar una vez en su programa, no cada vez que necesite un número aleatorio. La semilla más utilizada es la hora actual, convertida aint64
porUnixNanoconrand.Seed(time.Now().UnixNano())
:
package main
import (
“fmt”
“math/rand”
“time”
)
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
}
Recuerde que debido a su entorno de pruebas, Go Playground siempre comienza con la misma hora, por lo que este código no funcionará como se esperaba. Pruébelo en un entorno real, y los números que antes no cambiaban, ahora se imprimirán de manera diferente cada vez que ejecute el programa.
A continuación se enumeran algunos ejemplos comunes para facilitar su reutilización:
Genera un entero aleatorio
package main
import (
“fmt”
“math/rand”
“time”
)
// Returns an int >= min, < max
func randomInt(min, max int) int {
return min + rand.Intn(max-min)
}
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(randomInt(1, 11)) //get an int in the 1…10 range
}
Genera una cadena aleatoria
package main
import (
“fmt”
“math/rand”
“time”
)
// Returns an int >= min, < max
func randomInt(min, max int) int {
return min + rand.Intn(max-min)
}
// Generate a random string of A-Z chars with len = l
func randomString(len int) string {
bytes := make([]byte, len)
for i := 0; i < len; i++ {
bytes[i] = byte(randomInt(65, 90))
}
return string(bytes)
}
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(randomString(10)) // print 10 chars
}
Devolverá 10 caracteres en mayúsculas. Cambio
bytes[i] = byte(randomInt(65, 90))
a
bytes[i] = byte(randomInt(97, 122))
solo por minúsculas.
Si, en cambio, desea tener un grupo de caracteres específicos para elegir, use
package main
import (
“fmt”
“math/rand”
“time”
)
var pool = “_:$%&/()”
// Generate a random string of A-Z chars with len = l
func randomString(l int) string {
bytes := make([]byte, l)
for i := 0; i < l; i++ {
bytes[i] = pool[rand.Intn(len(pool))]
}
return string(bytes)
}
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(randomString(1000))
}
Cambiolen(pool)
autf8.RuneCountInString(pool)
si usa cadenas no ascii, comolen()
cuenta los bytes, pero no todos los caracteres toman solo un byte en Unicode - veahttps://stackoverflow.com/questions/12668681/how-to-get-the-number-of-characters-in-a-string.
Genera una matriz aleatoria de enteros
package main
import (
“fmt”
“math/rand”
“time”
)
func randomArray(len int) []int {
a := make([]int, len)
for i := 0; i <= len-1; i++ {
a[i] = rand.Intn(len)
}
return a
}
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(randomArray(10))
}
Números aleatorios a nivel criptográfico
Go también proporciona unGenerador de números pseudoaleatorios criptográficamente seguro (CSPRNG)en el paquete de biblioteca estándarcrypto.rand
Entonces, podría preguntarse, ¿por qué debería usar la biblioteca del generador aleatorio de pseudo-números proporcionada pormath/rand
¿en lugar de? Bueno, depende del caso de uso.math/rand
esmucho mas rápidopara aplicaciones que no necesitan generación de datos aleatorios de nivel criptográfico o relacionados con la seguridad.crypto.rand
es adecuado para un uso seguro y listo para criptografía, pero es más lento.
¿Para qué debe usarse? Por ejemplo, generar contraseñas, tokens CSRF, claves de sesión o cualquier cosa relacionada de forma remota con la seguridad.
No depende de la hora actual, como hicimos en los ejemplos anteriores enmath/rand
, pero en su lugar utiliza las API CSPRNG del sistema operativo: la API CryptGenRandom en Windows, y/dev/urandom/
en todos los demás (Linux, OSX, * nix)
Obtienes 256 bytes aleatorios directamente con
package main
import (
“crypto/rand”
“fmt”
)
func main() {
key := [256]byte{}
_, err := rand.Read(key[:])
if err != nil {
panic(err)
}
fmt.Println(key)
}
Estoy tomando una muestra de código deMatt Silverlock: puede hacerlo más general y crear una función de generación de bytes aleatorios
// GenerateRandomBytes returns securely generated random bytes.
// It will return an error if the system's secure random
// number generator fails to function correctly, in which
// case the caller should not continue.
func GenerateRandomBytes(n int) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
// Note that err == nil only if we read len(b) bytes.
if err != nil {
return nil, err
}
<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">b</span>, <span style="color:#66d9ef">nil</span>
}
y usando esto, una función de generación de cadenas aleatorias,
// GenerateRandomString returns a URL-safe, base64 encoded
// securely generated random string.
// It will return an error if the system's secure random
// number generator fails to function correctly, in which
// case the caller should not continue.
func GenerateRandomString(s int) (string, error) {
b, err := GenerateRandomBytes(s)
return base64.URLEncoding.EncodeToString(b), err
}
Más tutoriales de go:
- Uso de NGINX Reverse Proxy para brindar servicios de Go
- Hacer una copia de una estructura en Go
- Los conceptos básicos de un servidor web Go
- Ordenar un tipo de mapa en Go
- Ir consejos en pocas palabras
- Explicación de las etiquetas Go
- Ir al formato de fecha y hora
- Procesamiento JSON con Go
- Ir a funciones variadas
- Hoja de referencia de Go Strings
- Explicación de la interfaz Go Empty
- Depuración de Go con VS Code y Delve
- Parámetros de devoluciones de Go Named
- Generación de cadenas y números aleatorios en Go
- Estructura del sistema de archivos de un proyecto de Go
- Algoritmo de búsqueda binaria implementado en Go
- Uso de indicadores de línea de comando en Go
- GOPATH explicado
- Cree una aplicación de línea de comandos con Go: lolcat
- Construyendo un comando CLI con Go: cowsay
- Uso de Shell Pipes con Go
- Tutorial de Go CLI: clon de la fortuna
- Enumere los archivos en una carpeta con Go
- Use Ir para obtener una lista de repositorios de GitHub
- Ve, agrega un trozo de cadenas a un archivo
- Ve, convierte una cadena en un segmento de bytes
- Visualice sus contribuciones locales de Git con Go
- Introducción a la creación de perfiles de memoria y CPU de Go
- Resolver el error "no admite la indexación" en un programa Go
- Medir el tiempo de ejecución en un programa Go
- Creación de un rastreador web con Go para detectar títulos duplicados
- Siga las mejores prácticas: ¿puntero o receptores de valor?
- Siga las mejores prácticas: ¿Debería utilizar un método o una función?
- Ir a estructuras de datos: Establecer
- Hoja de referencia de Go Maps
- Genere implementaciones para tipos genéricos en Go
- Ir a estructuras de datos: diccionario
- Ir a estructuras de datos: tabla hash
- Implementar oyentes de eventos en canales de paso
- Ir a estructuras de datos: apilar
- Ir a estructuras de datos: cola
- Ir a estructuras de datos: árbol de búsqueda binaria
- Ir a estructuras de datos: gráfico
- Ir a estructuras de datos: lista vinculada
- La guía completa de Go Data Structures
- Comparación de valores de Go
- ¿Go está orientado a objetos?
- Trabajar con una base de datos SQL en Go
- Usar variables de entorno en Go
- Ir al tutorial: API REST respaldada por PostgreSQL
- Habilitación de CORS en un servidor web Go
- Implementación de una aplicación Go en un contenedor Docker
- Por qué Go es un lenguaje poderoso para aprender como desarrollador PHP
- Ve, elimina el carácter de nueva línea io.Reader.ReadString
- Ir, cómo ver los cambios y reconstruir su programa
- Ve, cuenta los meses desde una fecha
- Acceder a los parámetros HTTP POST en Go