J'essaie de convertir une chaîne renvoyée de flag.Arg(n)
en int
. Quelle est la manière idiomatique de faire cela dans Go?
Par exemple,
package main
import (
"flag"
"fmt"
"os"
"strconv"
)
func main() {
flag.Parse()
s := flag.Arg(0)
// string to int
i, err := strconv.Atoi(s)
if err != nil {
// handle error
fmt.Println(err)
os.Exit(2)
}
fmt.Println(s, i)
}
Le moyen le plus simple consiste à utiliser la fonction strconv.Atoi()
.
Notez qu'il existe de nombreuses autres manières. Par exemple, les commandes fmt.Sscan()
et strconv.ParseInt()
offrent une plus grande souplesse dans la mesure où vous pouvez spécifier la base et la taille en bits, par exemple. Aussi, comme indiqué dans la documentation de strconv.Atoi()
:
Atoi est un raccourci pour ParseInt (s, 10, 0).
Voici un exemple utilisant les fonctions mentionnées (essayez-le sur le Go Playground ):
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)
}
Sortie (si appelée avec l'argument "123"
):
i=123, type: int
i=123, type: int64
i=123, type: int
Il existe également un utilitaire fmt.Sscanf()
qui offre une flexibilité encore plus grande, car vous pouvez spécifier le format du numéro (comme la largeur, la base, etc.) ainsi que des caractères supplémentaires dans la variable string
.
C'est parfait pour analyser des chaînes personnalisées contenant un numéro. Par exemple, si votre entrée est fournie sous la forme "id:00123"
où vous avez un préfixe "id:"
et que le nombre est fixé à 5 chiffres, complétée par des zéros si elle est plus courte, ceci est très facilement analysable comme ceci:
s := "id:00123"
var i int
if _, err := fmt.Sscanf(s, "id:%5d", &i); err == nil {
fmt.Println(i) // Outputs 123
}
Voici trois manières d’analyser des chaînes en entiers, du plus rapide au plus lent:
strconv.ParseInt(...)
le plus rapidestrconv.Atoi(...)
toujours très rapidefmt.Sscanf(...)
Pas très rapide mais très flexibleVoici un point de repère qui montre l’utilisation et un exemple de minutage pour chaque fonction:
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)
}
}
}
Vous pouvez l'exécuter en enregistrant en tant que atoi_test.go
et en exécutant 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
Essaye ça
import ("strconv")
value : = "123"
number,err := strconv.ParseUint(value, 10, 32)
Si vous contrôlez les données d'entrée, vous pouvez utiliser la version mini
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
}
}
l'option la plus rapide (faites votre chèque si nécessaire). Résultat :
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