Skip to content

อินพุตเอาต์พุตใน Go

go
package main

import "fmt"

func main() {
   fmt.Println("Hello โลก!")
}

กรณีตัวอย่างแรก在本站คือการเอาต์พุตสตริงหนึ่งสตริง บทนี้จะกล่าวถึงวิธีการอินพุตเอาต์พุตใน Go

ตัวอธิบายไฟล์

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

ในแพ็กเกจ os มีตัวอธิบายไฟล์ที่เปิดเผยภายนอกสามตัว ประเภทของพวกมันคือ *os.File ได้แก่

  • os.Stdin - อินพุตมาตรฐาน
  • os.Stdout - เอาต์พุตมาตรฐาน
  • os.Stderr - ข้อผิดพลาดมาตรฐาน

อินพุตเอาต์พุตใน Go ไม่สามารถแยกจากพวกมันได้

เอาต์พุต

ใน Go มีวิธีการเอาต์พุตหลายวิธี ด้านล่างเป็นวิธีที่พบบ่อยบางวิธี

stdout

เนื่องจากเอาต์พุตมาตรฐานเป็นไฟล์อยู่แล้ว คุณสามารถเขียนสตริงลงในเอาต์พุตมาตรฐานได้โดยตรง

go
package main

import "os"

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

print

Go มีฟังก์ชันในตัวสองฟังก์ชัน print, println พวกมันจะเอาต์พุตพารามิเตอร์ไปยังข้อผิดพลาดมาตรฐาน ใช้สำหรับการดีบักเท่านั้น โดยทั่วไปไม่แนะนำให้ใช้

go
package main

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

fmt

วิธีที่ใช้บ่อยที่สุดคือการใช้แพ็กเกจ fmt มันมีฟังก์ชัน fmt.Println ซึ่งโดยค่าเริ่มต้นจะเอาต์พุตพารามิเตอร์ไปยังเอาต์พุตมาตรฐาน

go
package main

import "fmt"

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

พารามิเตอร์ของมันรองรับประเภทใดๆ หากประเภทใช้อินเทอร์เฟซ String จะเรียกเมธอด String เพื่อรับรูปแบบสตริงของมัน ดังนั้นเนื้อหาที่เอาต์พุตมีความสามารถในการอ่านสูง เหมาะสำหรับสถานการณ์ส่วนใหญ่ แต่เนื่องจากใช้การสะท้อนภายใน ไม่แนะนำให้ใช้จำนวนมากในสถานการณ์ที่อ่อนไหวต่อประสิทธิภาพ

bufio

bufio มีวิธีการเอาต์พุตแบบบัฟเฟอร์ มันจะเขียนข้อมูลลงในหน่วยความจำก่อน เมื่อสะสมถึงเกณฑ์ที่กำหนดจึงเอาต์พุตไปยัง Writer ที่กำหนด ขนาดบัฟเฟอร์เริ่มต้นคือ 4KB แนะนำให้ใช้แพ็กเกจนี้เมื่อทำ IO ไฟล์ หรือ IO เครือข่าย

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

คุณยังสามารถรวม它与แพ็กเกจ fmt ใช้ร่วมกันได้

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

การจัดรูปแบบ

ฟังก์ชันการจัดรูปแบบเอาต์พุตใน Go โดยพื้นฐานแล้วมีให้โดยฟังก์ชัน fmt.Printf หากคุณเรียนรู้ภาษาตระกูล C มาแล้ว จะต้องรู้สึกคุ้นเคย ด้านล่างเป็นตัวอย่างง่ายๆ

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

ด้านล่างเป็นคำกริยาการจัดรูปแบบทั้งหมดที่ Go มีในปัจจุบัน

0การจัดรูปแบบคำอธิบายประเภทที่รับ
1%%เอาต์พุตเครื่องหมายเปอร์เซ็นต์ %ใดๆ
2%sเอาต์พุตค่า string/[] bytestring,[] byte
3%qจัดรูปแบบสตริง สตริงที่เอาต์พุตมีเครื่องหมายอัญประกาศคู่ "" ล้อมรอบstring,[] byte
4%dเอาต์พุตค่าจำนวนเต็มฐานสิบจำนวนเต็ม
5%fเอาต์พุตจำนวนจริงจำนวนจริง
6%eเอาต์พุตในรูปแบบสัญกรณ์วิทยาศาสตร์ ใช้กับจำนวนเชิงซ้อนได้จำนวนจริง
7%Eเหมือนกับ %eจำนวนจริง
8%gตัดสินใจเอาต์พุต %f หรือ %e ตามสถานการณ์จริง จะลบ 0 ที่เกินออกจำนวนจริง
9%bเอาต์พุตในรูปแบบไบนารีของจำนวนเต็มตัวเลข
10%#bเอาต์พุตในรูปแบบไบนารีที่สมบูรณ์ตัวเลข
11%oเอาต์พุตในรูปแบบแปดฐานของจำนวนเต็มจำนวนเต็ม
12%#oเอาต์พุตในรูปแบบแปดฐานที่สมบูรณ์ของจำนวนเต็มจำนวนเต็ม
13%xเอาต์พุตในรูปแบบสิบหกฐานตัวเล็กของจำนวนเต็มตัวเลข
14%#xเอาต์พุตในรูปแบบสิบหกฐานตัวเล็กที่สมบูรณ์ของจำนวนเต็มตัวเลข
15%Xเอาต์พุตในรูปแบบสิบหกฐานตัวใหญ่ของจำนวนเต็มตัวเลข
16%#Xเอาต์พุตในรูปแบบสิบหกฐานตัวใหญ่ที่สมบูรณ์ของจำนวนเต็มตัวเลข
17%vเอาต์พุตในรูปแบบเดิมของค่า ส่วนใหญ่ใช้สำหรับการเอาต์พุตโครงสร้างข้อมูลใดๆ
18%+vเมื่อเอาต์พุตสตรักเจอร์จะเพิ่มชื่อฟิลด์ด้วยใดๆ
19%#vเอาต์พุตค่าในรูปแบบไวยากรณ์ Go ที่สมบูรณ์ใดๆ
20%tเอาต์พุตค่าบูลีนบูลีน
21%Tเอาต์พุตค่าประเภทภาษา Go ที่ตรงกับค่าใดๆ
22%cเอาต์พุตอักขระที่ตรงกับรหัส Unicodeint32
23%Uเอาต์พุตรหัส Unicode ที่ตรงกับอักขระrune,byte
24%pเอาต์พุตที่อยู่ของพอยน์เตอร์ที่ชี้พอยน์เตอร์

ใช้ fmt.Sprintf หรือ fmt.Printf เพื่อจัดรูปแบบสตริงหรือเอาต์พุตสตริงที่จัดรูปแบบ ดูตัวอย่างบางตัวอย่าง

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{})

เมื่อใช้ฐานอื่น สามารถเพิ่มช่องว่างระหว่าง % กับคำกริยาจัดรูปแบบเพื่อให้ได้ผลของตัวคั่น เช่น

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

ผลลัพธ์ของตัวอย่างนี้คือ

61626364656667
61 62 63 64 65 66 67

เมื่อใช้ตัวเลข ยังสามารถเติมศูนย์อัตโนมัติได้ เช่น

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

ไบนารีก็เช่นกัน

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

สถานการณ์ข้อผิดพลาด

จำนวนอักขระจัดรูปแบบ < จำนวนพารามิเตอร์ในรายการ

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

จำนวนอักขระจัดรูปแบบ > จำนวนพารามิเตอร์ในรายการ

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

ประเภทไม่ตรงกัน

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

ขาดคำกริยาจัดรูปแบบ

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

อินพุต

ด้านล่างแนะนำวิธีการอินพุตที่พบบ่อย

read

คุณสามารถอ่านเนื้อหาอินพุตเหมือนอ่านไฟล์โดยตรง ดังนี้

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

แบบนี้ใช้ยากเกินไป โดยทั่วไปไม่แนะนำให้ใช้

fmt

เราสามารถใช้ฟังก์ชันบางฟังก์ชันที่แพ็กเกจ fmt มีให้ ใช้คล้ายกับ C

go
// สแกนข้อความที่อ่านจาก os.Stdin แยกตามช่องว่าง ขึ้นบรรทัดใหม่ก็ถือเป็นช่องว่างด้วย
func Scan(a ...any) (n int, err error)

// คล้ายกับ Scan แต่หยุดการสแกนเมื่อพบการขึ้นบรรทัดใหม่
func Scanln(a ...any) (n int, err error)

// สแกนตามสตริงที่จัดรูปแบบ
func Scanf(format string, a ...any) (n int, err error)

อ่านตัวเลขสองตัว

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

อ่านอาร์เรย์ความยาวคงที่

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

เมื่อมีอินพุตจำนวนมากที่ต้องอ่าน แนะนำให้ใช้ bufio.Reader เพื่ออ่านเนื้อหา

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 คล้ายกับ bufio.Reader แต่จะอ่านทีละบรรทัด

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

ผลลัพธ์ดังนี้

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

TIP

ในด้านการอินพุตเอาต์พุตนี้ หากต้องการฝึกฝน ไปที่ 洛谷 ทำโจทย์อัลกอริทึมโหมด ACM ง่ายๆ สองสามข้อก็จะคุ้นเคยได้

Golang by www.golangdev.cn edit