سؤال
أبحث عن تعادل SCANF (). حاولت مع التعليمات البرمجية التالية:
1 package main
2
3 import (
4 "scanner"
5 "os"
6 "fmt"
7 )
8
9 func main() {
10 var s scanner.Scanner
11 s.Init(os.Stdin)
12 s.Mode = scanner.ScanInts
13 tok := s.Scan()
14 for tok != scanner.EOF {
15 fmt.Printf("%d ", tok)
16 tok = s.Scan()
17 }
18 fmt.Println()
19 }
قمت بتشغيله بإدخال نص من النص مع مجموعة من الأعداد الصحيحة. لكنه دائما إخراج -3 -3 ...
وكيفية مسح خط يتكون من سلسلة وبعض الأعداد الصحيحة؟ تغيير الوضع كلما صادف نوع بيانات جديد؟
وثائق الحزمة:
الحزمة الماسح الضوئي
الماسح الضوئي للأغراض العامة للنص المشفر UTF-8.
ولكن يبدو أن الماسح الضوئي ليس للاستخدام العام.
رمز محدث:
func main() {
n := scanf()
fmt.Println(n)
fmt.Println(len(n))
}
func scanf() []int {
nums := new(vector.IntVector)
reader := bufio.NewReader(os.Stdin)
str, err := reader.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
i, _ := strconv.Atoi(f)
nums.Push(i)
}
str, err = reader.ReadString('\n')
}
r := make([]int, nums.Len())
for i := 0; i < nums.Len(); i++ {
r[i] = nums.At(i)
}
return r
}
نسخة محسنة:
package main
import (
"bufio"
"os"
"io"
"fmt"
"strings"
"strconv"
"container/vector"
)
func main() {
n := fscanf(os.Stdin)
fmt.Println(len(n), n)
}
func fscanf(in io.Reader) []int {
var nums vector.IntVector
reader := bufio.NewReader(in)
str, err := reader.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
if i, err := strconv.Atoi(f); err == nil {
nums.Push(i)
}
}
str, err = reader.ReadString('\n')
}
return nums
}
المحلول
كان الرمز المحدث الخاص بك هو أسهل بكثير الترجمة دون أرقام السطر، لكنه كان يفتقد عبارات الحزمة والاستيراد.
النظر في التعليمات البرمجية الخاصة بك، لاحظت بعض الأشياء. إليك الإصدار المنقح الخاص بي من التعليمات البرمجية الخاصة بك.
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
"container/vector"
)
func main() {
n := scanf(os.Stdin)
fmt.Println()
fmt.Println(len(n), n)
}
func scanf(in io.Reader) []int {
var nums vector.IntVector
rd := bufio.NewReader(os.Stdin)
str, err := rd.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
if i, err := strconv.Atoi(f); err == nil {
nums.Push(i)
}
}
str, err = rd.ReadString('\n')
}
return nums
}
قد أرغب في استخدام أي ملف إدخال ل scanf()
, ، ليس مجرد Stdin
; scanf()
يأخذ io.Reader
كمعلمة.
انت كتبت: nums := new(vector.IntVector)
, ، أين type IntVector []int
. وبعد هذا يخصص مرجع شريحة عددا صحيحا اسمه nums
وتهيئة ذلك إلى الصفر، ثم new()
وظيفة تخصيص إشارة شريحة عدد صحيح وتهيئةها إلى الصفر، ثم تعينها nums
. وبعد كتبت: var nums vector.IntVector
, ، والتي تتجنب التكرار عن طريق تخصيص إشارة شريحة عدد صحيح باسم nums
وتهيئة ذلك إلى الصفر.
أنت لم تحقق err
القيمة ل strconv.Atoi()
, ، مما يعني أن إدخال غير صالح تم تحويله إلى قيمة صفرية؛ أنا تخطي ذلك.
لنسخ من المتجه إلى شريحة جديدة وإرجاع الشريحة، كتبت:
r := make([]int, nums.Len())
for i := 0; i < nums.Len(); i++ {
r[i] = nums.At(i)
}
return r
أولا، ببساطة استبدال ذلك مع ما يعادلها، IntVector.Data()
طريقة: return nums.Data()
. وبعد بعد ذلك، استفادت من حقيقة ذلك type IntVector []int
وتجنب التخصيص والنسخ عن طريق استبدال ذلك ب: return nums
.
نصائح أخرى
على الرغم من أنه يمكن استخدامه لأشياء أخرى، تم تصميم حزمة الماسح الضوئي لمسح نص البرنامج. Ints (-123)، chars ('c')، السلاسل ("str")، وما إلى ذلك تذهب أنواع رمزية اللغة.
package main
import (
"fmt"
"os"
"scanner"
"strconv"
)
func main() {
var s scanner.Scanner
s.Init(os.Stdin)
s.Error = func(s *scanner.Scanner, msg string) { fmt.Println("scan error", msg) }
s.Mode = scanner.ScanInts | scanner.ScanStrings | scanner.ScanRawStrings
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
txt := s.TokenText()
fmt.Print("token:", tok, "text:", txt)
switch tok {
case scanner.Int:
si, err := strconv.Atoi64(txt)
if err == nil {
fmt.Print(" integer: ", si)
}
case scanner.String, scanner.RawString:
fmt.Print(" string: ", txt)
default:
if tok >= 0 {
fmt.Print(" unicode: ", "rune = ", tok)
} else {
fmt.Print(" ERROR")
}
}
fmt.Println()
}
}
يقرأ هذا المثال دائما في سطر في وقت واحد وإرجاع السطر بأكمله كسلسلة. إذا كنت ترغب في تحليل قيم محددة منه، يمكنك.
package main
import (
"fmt"
"bufio"
"os"
"strings"
)
func main() {
value := Input("Please enter a value: ")
trimmed := strings.TrimSpace(value)
fmt.Printf("Hello %s!\n", trimmed)
}
func Input(str string) string {
print(str)
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
return input
}
في تعليق لأحد إجاباتي، قلت:
من مواصفات اللغة: "عندما يتم تخصيص الذاكرة لتخزين قيمة، إما من خلال إعلان أو إجراء () أو إجراء () أو جديد ()، ولا يتم توفير تهيئة صريحة، يتم إعطاء الذاكرة تهيئة افتراضية". ثم ما هي نقطة جديدة ()؟
إذا جرينا:
package main
import ("fmt")
func main() {
var i int
var j *int
fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j)
j = new(int)
fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j, "; *j (a value) = ", *j)
}
الإعلان var i int
يخصص الذاكرة لتخزين قيمة عدد صحيح وتهيئة القيمة إلى الصفر. الإعلان var j *int
يخصص الذاكرة لتخزين مؤشر إلى قيمة عدد صحيح وتهيئة المؤشر إلى الصفر (مؤشر NIL)؛ لا يتم تخصيص أي ذاكرة لتخزين قيمة عدد صحيح. نرى إخراج البرنامج على غرار:
i (a value) = 0 ; j (a pointer) = <nil>
وظيفة المدمج new
يأخذ نوع T
وإرجاع قيمة النوع *T
. وبعد تتم تهيئة الذاكرة إلى قيم صفر. البيان j = new(int)
يخصص الذاكرة لتخزين قيمة عدد صحيح وتهيئة القيمة إلى الصفر، ثم يخزن مؤشر إلى هذه القيمة الصحيحة في J. نرى إخراج البرنامج على غرار:
i (a value) = 0 ; j (a pointer) = 0x7fcf913a90f0 ; *j (a value) = 0
أضاف أحدث إصدار من الذهاب (2010-05-27) وظيفتين ل fmt
صفقة: Scan()
و Scanln()
. وبعد انهم لا يأخذون أي سلسلة نمط. مثل في C، ولكن يتحقق من نوع الحجج بدلا من ذلك.
package main
import (
"fmt"
"os"
"container/vector"
)
func main() {
numbers := new(vector.IntVector)
var number int
n, err := fmt.Scan(os.Stdin, &number)
for n == 1 && err == nil {
numbers.Push(number)
n, err = fmt.Scan(os.Stdin, &number)
}
fmt.Printf("%v\n", numbers.Data())
}