Go nunca convierte tipos de forma implícita. Conviertes entre tipos compatibles con T(v), y entre números y texto con el paquete strconv. Las dos conversiones más buscadas:
strconv.Itoa ("integer to ASCII") formatea un int como texto decimal. strconv.Atoi ("ASCII to integer") analiza texto y lo convierte en un int, y devuelve un error cuando el texto no es un número válido. Comprueba siempre ese error.
La conversión T(v)
La sintaxis de conversión de Go parece una llamada a una función con el nombre del tipo de destino. Funciona en tres situaciones:
- entre tipos numéricos (
int,int64,float64,uint8, ...), - entre
stringy[]byteo[]rune, - entre tipos que comparten tipo subyacente (
Celsiusyfloat64).
Lee los resultados con atención:
int(3.9)es3eint(-3.9)es-3. La conversión trunca hacia cero; no redondea. Usa antesmath.Round,math.Flooromath.Ceilpara elegir el comportamiento.math.Roundredondea la mitad alejándose de cero, así que-3.5se convierte en-4.uint8(300)es44, porque solo sobreviven los 8 bits bajos (300 menos 256), eint8(200)es-56por la misma razón. Ni error ni panic.Celsiusyfloat64comparten tipo subyacente, así que se convierten libremente, pero solo de forma explícita.
Los valores están en variables a propósito. Con constantes, las mismas conversiones no compilan.
Las constantes se comprueban, las variables no
Convertir una constante que no cabe es un error de compilación. Convertir una variable con el mismo valor da la vuelta en silencio:
fmt.Println(uint8(300)) // compile error
x := 300
fmt.Println(uint8(x)) // 44
./main.go:6:20: constant 300 overflows uint8
Convertir una constante no entera a un tipo entero también se rechaza, mientras que el mismo valor en una variable se trunca:
./main.go:7:18: cannot convert -3.9 (untyped float constant) to type int
Si el valor flotante está fuera del rango del tipo entero de destino (por ejemplo int64(1e20)), el resultado depende de la implementación: amd64 y arm64, por ejemplo, dan respuestas distintas. Comprueba el rango antes de convertir valores no fiables.
Convertir números en strings
| Desde | Función | Ejemplo | Resultado |
|---|---|---|---|
int | strconv.Itoa(n) | strconv.Itoa(-7) | "-7" |
int64 | strconv.FormatInt(n, base) | strconv.FormatInt(255, 16) | "ff" |
uint64 | strconv.FormatUint(n, base) | strconv.FormatUint(5, 2) | "101" |
float64 | strconv.FormatFloat(f, fmt, prec, 64) | strconv.FormatFloat(3.14159, 'f', 2, 64) | "3.14" |
bool | strconv.FormatBool(b) | strconv.FormatBool(true) | "true" |
| cualquier cosa | fmt.Sprint(v) | fmt.Sprint(3.5) | "3.5" |
| cualquier cosa, con formato | fmt.Sprintf(format, v) | fmt.Sprintf("%05d", 42) | "00042" |
FormatFloat recibe un byte de formato ('f' para notación fija, 'e' para exponente, 'g' para la más corta de las dos), una precisión (-1 significa "los menos dígitos que permiten recuperar el valor exacto") y el tamaño en bits del float original (64 o 32).
strconv es más rápido que fmt.Sprint, que mete el valor en una interfaz y pasa por la ruta de formato general de fmt. En un bucle caliente esa diferencia se nota; para conversiones ocasionales, elige lo que se lea mejor.
Convertir strings en números
| A | Función | Devuelve |
|---|---|---|
int | strconv.Atoi(s) | int, error |
| cualquier entero con signo | strconv.ParseInt(s, base, bitSize) | int64, error |
| cualquier entero sin signo | strconv.ParseUint(s, base, bitSize) | uint64, error |
| float | strconv.ParseFloat(s, bitSize) | float64, error |
| bool | strconv.ParseBool(s) | bool, error |
ParseInt siempre devuelve un int64. El argumento bitSize (0, 8, 16, 32, 64) fija el rango que acepta, así que el resultado cabe con seguridad cuando lo conviertes a un tipo más pequeño. base 0 significa "deducirla del prefijo", así que 0x1f, 0o17, 0b101 y 1_000 se analizan todos.
Cosas que muestra la salida:
" 42"falla.Atoiacepta un signo opcional y dígitos, nada más. La entrada debufiosuele terminar en\n, así que recórtala."4.2"no es válido paraAtoi. UsaParseFloatpara decimales.- Ante un error de fuera de rango,
ParseIntdevuelve el mayor valor que cabe (127paraint8) junto con el error. No uses el valor cuando el error no sea nil. - Los errores son valores
*strconv.NumErrorque envuelvenstrconv.ErrSyntaxostrconv.ErrRange, así queerrors.Ispuede distinguirlos.
ParseBool acepta 1, t, T, TRUE, true, True y las formas equivalentes para false. "yes" y "on" son errores.
La trampa de string(65)
Convertir un entero a string no produce dígitos. Produce el carácter con ese code point Unicode:
n := 65
s := string(n) // "A", not "65"
El compilador lo acepta, pero go vet lo informa:
./main.go:10:7: conversion from int to string yields a string of one rune, not a string of digits
Si de verdad quieres el carácter, dilo con un rune: string(rune(n)). Si quieres el número como texto, usa strconv.Itoa(n). Convertir un rune o un byte a string es correcto y habitual:
Strings, bytes y runes
string, []byte y []rune se convierten entre sí con T(v). Cada conversión copia los datos, porque los strings son inmutables y los slices no:
Convierte a []rune cuando necesites indexar o modificar por carácter; convierte a []byte para I/O, hashing y ediciones a nivel de byte. La página de runes y bytes explica UTF-8 en detalle.
Conversión frente a aserción de tipo
Una conversión cambia un valor de un tipo concreto a otro. Sacar el valor concreto de una interfaz (any, error, io.Reader) es una operación distinta, la aserción de tipo:
var v any = 42
n := v.(int) // type assertion: v holds an int, give it to me
f := float64(n) // conversion: int to float64
// f := float64(v) // compile error: cannot convert v (variable of interface type any)
// // to type float64: need type assertion
Primero la aserción, luego la conversión. La forma comma-ok n, ok := v.(int) evita un panic cuando el tipo es incorrecto.
Referencia rápida
| Tarea | Código |
|---|---|
| int a string | strconv.Itoa(n) |
| int64 a string | strconv.FormatInt(n, 10) |
| string a int | n, err := strconv.Atoi(s) |
| string a int64 | n, err := strconv.ParseInt(s, 10, 64) |
| string a float64 | f, err := strconv.ParseFloat(s, 64) |
| float64 a string | strconv.FormatFloat(f, 'f', -1, 64) |
| float64 a int | int(f) (trunca) o int(math.Round(f)) |
| int a float64 | float64(n) |
| string a []byte | []byte(s) |
| []byte a string | string(b) |
| rune a string | string(r) |
| bool a string | strconv.FormatBool(b) |
| cualquier valor a string | fmt.Sprint(v) |
Preguntas frecuentes
¿Cómo convierto un int en un string en Go?
Usa strconv.Itoa(n): strconv.Itoa(42) devuelve "42". Para un int64 usa strconv.FormatInt(n, 10). fmt.Sprint(n) también funciona con cualquier tipo, pero es más lento. No escribas string(n): eso trata n como un code point Unicode, así que string(65) es "A".
¿Cómo convierto un string en un int en Go?
Usa strconv.Atoi, que devuelve el número y un error:
n, err := strconv.Atoi("42")
if err != nil {
// not a valid integer
}
Para un tamaño o una base concretos, usa strconv.ParseInt(s, 10, 64), que devuelve un int64. Atoi no recorta espacios, así que " 42" da error; llama antes a strings.TrimSpace.
¿Cómo hago un cast en Go?
Go lo llama conversión, y la sintaxis es T(v): float64(n), int(f), []byte(s). Funciona entre tipos numéricos, entre strings y slices de bytes o de runes, y entre tipos con el mismo tipo subyacente. No analiza texto: convertir "42" en 42 necesita strconv. Sacar un tipo concreto de una interfaz es una aserción de tipo, v.(T), no una conversión.
¿Cómo convierto un float en un int en Go?
int(f) trunca hacia cero: int(3.9) es 3 e int(-3.9) es -3. Para redondear, usa int(math.Round(f)). Si el float está fuera del rango del tipo entero, el resultado depende de la implementación, así que comprueba antes el rango cuando el valor venga de la entrada.
¿Por qué string(65) devuelve "A" en Go?
Convertir un entero a string lo interpreta como un code point Unicode, y 65 es el code point de A. go vet lo marca: conversion from int to string yields a string of one rune, not a string of digits. Usa strconv.Itoa(65) para obtener "65".