Skip to content

Entrada y salida en Go

go
package main

import "fmt"

func main() {
   fmt.Println("Hello Mundo!")
}

El primer ejemplo introductorio de este sitio es imprimir una cadena, esta sección explicará cómo realizar entrada y salida en Go.

Descriptores de archivo

go
var (
   Stdin  = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
   Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
   Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)

En el paquete os hay tres descriptores de archivo expuestos, todos de tipo *os.File, que son:

  • os.Stdin - Entrada estándar
  • os.Stdout - Salida estándar
  • os.Stderr - Error estándar

La entrada y salida en Go dependen de ellos.

Salida

En Go hay muchas formas de realizar la salida, aquí se presentan algunas de las más comunes

stdout

Como la salida estándar en sí es un archivo, puedes escribir directamente en la salida estándar

go
package main

import "os"

func main() {
  os.Stdout.WriteString("hello world!")
}

print

Go tiene dos funciones incorporadas print y println, que envían los parámetros al error estándar, solo para depuración, generalmente no se recomienda su uso.

go
package main

func main() {
  print("hello world!\n")
  println("hello world")
}

fmt

El uso más común es el paquete fmt, que proporciona la función fmt.Println, que por defecto envía los parámetros a la salida estándar.

go
package main

import "fmt"

func main() {
  fmt.Println("hello world!")
}

Sus parámetros soportan cualquier tipo, si el tipo implementa la interfaz String también llamará al método String para obtener su representación en cadena, por lo que el contenido que imprime es bastante legible, adecuado para la mayoría de los casos, sin embargo, como usa reflexión internamente, no se recomienda su uso intensivo en escenarios sensibles al rendimiento.

bufio

bufio proporciona métodos de salida con búfer, primero escribe los datos en memoria, y cuando se acumula hasta cierto umbral los envía al Writer especificado, el tamaño de búfer por defecto es 4KB. Se recomienda usar este paquete para operaciones de E/S de archivos y redes.

go
func main() {
  writer := bufio.NewWriter(os.Stdout)
  defer writer.Flush()
  writer.WriteString("hello world!")
}

También puedes combinarlo con el paquete fmt

go
func main() {
  writer := bufio.NewWriter(os.Stdout)
  defer writer.Flush()
  fmt.Fprintln(writer, "hello world!")
}

Formateo

La funcionalidad de formateo de salida en Go es básicamente proporcionada por la función fmt.Printf. Si has aprendido lenguajes de la familia C, te resultará familiar, aquí hay un ejemplo simple.

go
func main() {
  fmt.Printf("hello world, %s!", "jack")
}

A continuación se muestran todos los verbos de formateo actuales de Go.

0FormatoDescripciónTipo recibido
1%%Imprime el signo de porcentaje %Cualquiera
2%sImprime valores string/[] bytestring,[] byte
3%qFormatea cadena, la cadena impresa tiene comillas dobles "" en ambos extremosstring,[] byte
4%dImprime valor entero en decimalEntero
5%fImprime número de punto flotantePunto flotante
6%eImprime en notación científica, también se puede usar para números complejosPunto flotante
7%EIgual que %ePunto flotante
8%gSegún la situación decide imprimir %f o %e, eliminará los ceros innecesariosPunto flotante
9%bImprime la representación binaria de un enteroNúmero
10%#bImprime la representación binaria completaNúmero
11%oImprime la representación octal de un enteroEntero
12%#oImprime la representación octal completa de un enteroEntero
13%xImprime la representación hexadecimal en minúsculas de un enteroNúmero
14%#xImprime la representación hexadecimal completa en minúsculas de un enteroNúmero
15%XImprime la representación hexadecimal en mayúsculas de un enteroNúmero
16%#XImprime la representación hexadecimal completa en mayúsculas de un enteroNúmero
17%vImprime el valor en su forma original, principalmente usado para imprimir estructuras de datosCualquiera
18%+vAl imprimir estructuras agregará los nombres de los camposCualquiera
19%#vImprime el valor en formato completo de sintaxis GoCualquiera
20%tImprime valor booleanoBooleano
21%TImprime el tipo Go correspondiente al valorCualquiera
22%cImprime el carácter correspondiente al código Unicodeint32
23%UImprime el código Unicode correspondiente al carácterrune,byte
24%pImprime la dirección apuntada por el punteroPuntero

Usa fmt.Sprintf o fmt.Printf para formatear cadenas o imprimir cadenas formateadas, veamos algunos ejemplos

go
fmt.Printf("%%%s\n", "hello world")

fmt.Printf("%s\n", "hello world")
fmt.Printf("%q\n", "hello world")
fmt.Printf("%d\n", 2<<7-1)

fmt.Printf("%f\n", 1e2)
fmt.Printf("%e\n", 1e2)
fmt.Printf("%E\n", 1e2)
fmt.Printf("%g\n", 1e2)

fmt.Printf("%b\n", 2<<7-1)
fmt.Printf("%#b\n", 2<<7-1)
fmt.Printf("%o\n", 2<<7-1)
fmt.Printf("%#o\n", 2<<7-1)
fmt.Printf("%x\n", 2<<7-1)
fmt.Printf("%#x\n", 2<<7-1)
fmt.Printf("%X\n", 2<<7-1)
fmt.Printf("%#X\n", 2<<7-1)

type person struct {
    name    string
    age     int
    address string
}
fmt.Printf("%v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%+v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%#v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%t\n", true)
fmt.Printf("%T\n", person{})
fmt.Printf("%c%c\n", 20050, 20051)
fmt.Printf("%U\n", '')
fmt.Printf("%p\n", &person{})

Al usar otras bases, agregar un espacio entre % y el verbo de formateo puede lograr el efecto de separador, por ejemplo

go
func main() {
  str := "abcdefg"
  fmt.Printf("%x\n", str)
  fmt.Printf("% x\n", str)
}

El resultado de este ejemplo es

61626364656667
61 62 63 64 65 66 67

Al usar números, también se puede agregar ceros automáticamente. Por ejemplo

go
fmt.Printf("%09d", 1)
// 000000001

Igual para binario

go
fmt.Printf("%09b", 1<<3)
// 000001000

Casos de error

Cantidad de caracteres de formateo < cantidad de parámetros

go
fmt.Printf("", "") //%!(EXTRA string=)

Cantidad de caracteres de formateo > cantidad de parámetros

go
fmt.Printf("%s%s", "") //%!s(MISSING)

Tipo no coincidente

go
fmt.Printf("%s", 1) //%!s(int=1)

Falta verbo de formateo

go
fmt.Printf("%", 1) // %!(NOVERB)%!(EXTRA int=1)

Entrada

A continuación se presentan métodos comunes de entrada

read

Puedes leer el contenido de entrada directamente como si leyeras un archivo, de la siguiente manera

go
func main() {
  var buf [1024]byte
  n, _ := os.Stdin.Read(buf[:])
  os.Stdout.Write(buf[:n])
}

Es muy engorroso de usar, generalmente no se recomienda.

fmt

Podemos usar varias funciones proporcionadas por el paquete fmt, se usan de manera similar a C.

go
// Escanea el texto leído de os.Stdin, separa por espacios, el salto de línea también se considera espacio
func Scan(a ...any) (n int, err error)

// Similar a Scan, pero detiene el escaneo al encontrar un salto de línea
func Scanln(a ...any) (n int, err error)

// Escanea según una cadena de formateo
func Scanf(format string, a ...any) (n int, err error)

Leer dos números

go
func main() {
  var a, b int
  fmt.Scanln(&a, &b)
  fmt.Printf("%d + %d = %d\n", a, b, a+b)
}

Leer un array de longitud fija

go
func main() {
  n := 10
  s := make([]int, n)
  for i := range n {
    fmt.Scan(&s[i])
  }
  fmt.Println(s)
}
1 2 3 4 5 6 7 8 9 10
[1 2 3 4 5 6 7 8 9 10]

bufio

Cuando hay mucha entrada para leer, se recomienda usar bufio.Reader para leer el contenido

go
func main() {
    reader := bufio.NewReader(os.Stdin)
    var a, b int
    fmt.Fscanln(reader, &a, &b)
    fmt.Printf("%d + %d = %d\n", a, b, a+b)
}

scanner

bufio.Scanner es similar a bufio.Reader, pero lee línea por línea.

go
func main() {
  scanner := bufio.NewScanner(os.Stdin)
  for scanner.Scan() {
    line := scanner.Text()
    if line == "exit" {
      break
    }
    fmt.Println("scan", line)
  }
}

El resultado es

first line
scan first line
second line
scan second line
third line
scan third line
exit

TIP

En cuanto a entrada y salida, si quieres practicar, ve a Luogu y resuelve algunos problemas de algoritmos simples en modo ACM para familiarizarte.

Golang editado por www.golangdev.cn