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. يُنصح باستخدام هذه الحزمة في عمليات إدخال/إخراج الملفات والشبكة:

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، يزيل الأصفار الزائدةفاصلة عائمة
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 تم تحريره بواسطة www.golangdev.cn