Ich versuche, einen String zu konvertieren, der von flag.Arg(n)
zu einer int
. Was ist der idiomatische Weg, dies in Go zu tun?
Antworten
Zu viele Anzeigen?Zum Beispiel strconv.Atoi
.
Code:
package main
import (
"fmt"
"strconv"
)
func main() {
s := "123"
// string to int
i, err := strconv.Atoi(s)
if err != nil {
// ... handle error
panic(err)
}
fmt.Println(s, i)
}
Konvertierung einfacher Zeichenketten
Der einfachste Weg ist die Verwendung der strconv.Atoi()
Funktion.
Es gibt aber noch viele andere Möglichkeiten. Zum Beispiel fmt.Sscan()
y strconv.ParseInt()
die eine größere Flexibilität bieten, da Sie zum Beispiel die Basis und die Bitgröße angeben können. Wie auch in der Dokumentation von strconv.Atoi()
:
Atoi ist äquivalent zu ParseInt(s, 10, 0), konvertiert in den Typ int.
Hier ist ein Beispiel, das die genannten Funktionen verwendet (probieren Sie es auf dem Go Spielplatz ):
flag.Parse()
s := flag.Arg(0)
if i, err := strconv.Atoi(s); err == nil {
fmt.Printf("i=%d, type: %T\n", i, i)
}
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
fmt.Printf("i=%d, type: %T\n", i, i)
}
var i int
if _, err := fmt.Sscan(s, &i); err == nil {
fmt.Printf("i=%d, type: %T\n", i, i)
}
Ausgabe (bei Aufruf mit Argument "123"
):
i=123, type: int
i=123, type: int64
i=123, type: int
Analyse von benutzerdefinierten Zeichenfolgen
Außerdem gibt es eine praktische fmt.Sscanf()
die eine noch größere Flexibilität bietet, da Sie mit dem Formatstring das Zahlenformat (wie Breite, Basis usw.) zusammen mit zusätzlichen Zeichen in der Eingabe angeben können string
.
Dies ist ideal für das Parsen von benutzerdefinierten Zeichenketten, die eine Zahl enthalten. Zum Beispiel, wenn Ihre Eingabe in Form von "id:00123"
wo Sie ein Präfix haben "id:"
und die Zahl ist fest 5-stellig, mit Nullen aufgefüllt, wenn sie kürzer ist, lässt sie sich sehr leicht wie folgt analysieren:
s := "id:00123"
var i int
if _, err := fmt.Sscanf(s, "id:%5d", &i); err == nil {
fmt.Println(i) // Outputs 123
}
Hier sind drei Möglichkeiten, Zeichenketten in Ganzzahlen zu parsen, von der schnellsten bis zur langsamsten Laufzeit:
strconv.ParseInt(...)
schnellstestrconv.Atoi(...)
immer noch sehr schnellfmt.Sscanf(...)
nicht sonderlich schnell, aber sehr flexibel
Hier ist ein Benchmark, der die Verwendung und den Zeitplan für jede Funktion zeigt:
package main
import "fmt"
import "strconv"
import "testing"
var num = 123456
var numstr = "123456"
func BenchmarkStrconvParseInt(b *testing.B) {
num64 := int64(num)
for i := 0; i < b.N; i++ {
x, err := strconv.ParseInt(numstr, 10, 64)
if x != num64 || err != nil {
b.Error(err)
}
}
}
func BenchmarkAtoi(b *testing.B) {
for i := 0; i < b.N; i++ {
x, err := strconv.Atoi(numstr)
if x != num || err != nil {
b.Error(err)
}
}
}
func BenchmarkFmtSscan(b *testing.B) {
for i := 0; i < b.N; i++ {
var x int
n, err := fmt.Sscanf(numstr, "%d", &x)
if n != 1 || x != num || err != nil {
b.Error(err)
}
}
}
Sie können es ausführen, indem Sie speichern als atoi_test.go
und Laufen go test -bench=. atoi_test.go
.
goos: darwin
goarch: amd64
BenchmarkStrconvParseInt-8 100000000 17.1 ns/op
BenchmarkAtoi-8 100000000 19.4 ns/op
BenchmarkFmtSscan-8 2000000 693 ns/op
PASS
ok command-line-arguments 5.797s
Wenn Sie die Eingabedaten kontrollieren, können Sie die Miniversion verwenden
package main
import (
"testing"
"strconv"
)
func Atoi (s string) int {
var (
n uint64
i int
v byte
)
for ; i < len(s); i++ {
d := s[i]
if '0' <= d && d <= '9' {
v = d - '0'
} else if 'a' <= d && d <= 'z' {
v = d - 'a' + 10
} else if 'A' <= d && d <= 'Z' {
v = d - 'A' + 10
} else {
n = 0; break
}
n *= uint64(10)
n += uint64(v)
}
return int(n)
}
func BenchmarkAtoi(b *testing.B) {
for i := 0; i < b.N; i++ {
in := Atoi("9999")
_ = in
}
}
func BenchmarkStrconvAtoi(b *testing.B) {
for i := 0; i < b.N; i++ {
in, _ := strconv.Atoi("9999")
_ = in
}
}
die schnellste Option (stellen Sie ggf. einen Scheck aus). Ergebnis :
Path>go test -bench=. atoi_test.go
goos: windows
goarch: amd64
BenchmarkAtoi-2 100000000 14.6 ns/op
BenchmarkStrconvAtoi-2 30000000 51.2 ns/op
PASS
ok path 3.293s