Jaka jest różnica między int i int64 w Go?

86

Mam ciąg zawierający liczbę całkowitą (która została odczytana z pliku).

Próbuję przekonwertować stringplik intusing strconv.ParseInt(). ParseIntwymaga podania rozmiaru bitu (rozmiary bitów 0, 8, 16, 32 i 64 odpowiadają int, int8, int16, int32 i int64).

Odczytana z pliku liczba całkowita jest mała (tzn. Powinna mieścić się w normalnej liczbie całkowitej). Jeśli jednak przekażę rozmiar bitu równy 0, otrzymam wynik typu int64(prawdopodobnie dlatego, że pracuję na 64-bitowym systemie operacyjnym).

Dlaczego to się dzieje? Jak uzyskać normalne int? (Jeśli ktoś ma krótkie wprowadzenie na temat tego, kiedy i dlaczego powinienem używać różnych typów int, byłoby to niesamowite!)

Edycja: mogę przekonwertować int64 na normalny int używając int([i64_var]). Ale nadal nie rozumiem, dlaczego ParseInt()podaje mi int64, gdy żądam rozmiaru bitu 0.

Isaac Dontje Lindell
źródło
2
Używać Atoi dla zwięzłości? Ponadto, czy funkcja ParseInt zwraca błąd?
Matt,
2
Okej, teraz jestem trochę zdezorientowany. Jeśli używam Atoi (), daje mi int i wszystko działa. I wołał parseInt(s, 0, 0), która powinna wnioskować Base10 (ponieważ łańcuch nie posiada prefiksu bazowej). Jednak Atoi jest skrótem do wywoływania parseIntz liczbą 10. Dlaczego parametr bazowy ma wpływ na zwracany typ?
Isaac Dontje Lindell
Podstawowy parametr określa, w jaki sposób odczytywany jest ciąg wejściowy. Ciąg może wyglądać jak „123”, „0xBEEFCAKE”, „1011101” lub „0677”. Wszystkie mają inne znaczenie i dają inną wartość liczbową. Wartość podstawowa 0oznacza, że ​​kod próbuje sam to rozgryźć. Ale czasami nie jest to możliwe. 11(dziesiętne) vs 11(binarne) reprezentują zupełnie inne wartości.
jimt
1
Okej, myślę, że naprawdę jestem zdezorientowany, to doktorzy. Dokumenty dotyczące Atoi mówią tylko, że jest to tylko „skrót od parseInt(s, 10, 0)”. Ale dlaczego w takim razie Atoi wraca, inta parseIntzwraca int64?
Isaac Dontje Lindell
1
Nie wiedząc dokładnie dlaczego, przyjmuję, że Atoizostało to dodane tylko po to, aby pomieścić ludzi, którzy są bardziej zaznajomieni z C API:int atoi ( const char * str );
jimt

Odpowiedzi:

55
func ParseInt(s string, base int, bitSize int) (i int64, err error)

ParseInt zawsze zwraca int64

bitSizeokreśla zakres wartości. Jeśli wartość odpowiadająca s nie może być reprezentowana przez liczbę całkowitą ze znakiem danego rozmiaru, err.Err = ErrRange.

http://golang.org/pkg/strconv/#ParseInt

type int int

int to liczba całkowita ze znakiem o rozmiarze co najmniej 32 bitów. Jest to jednak odrębny typ, a nie alias, powiedzmy, int32.

http://golang.org/pkg/builtin/#int

Więc intmoże być większy niż 32-bitowy w przyszłości lub w niektórych systemach, takich jak intC.

Myślę, że w niektórych systemach int64może być szybszy niż int32dlatego, że ten system działa tylko z 64-bitowymi liczbami całkowitymi.

Oto przykład błędu, gdy bitSizewynosi 8

http://play.golang.org/p/_osjMqL6Nj

package main

import (
    "fmt"
    "strconv"
)

func main() {
    i, err := strconv.ParseInt("123456", 10, 8)
    fmt.Println(i, err)
}
Shuriken
źródło
22
W praktyce zazwyczaj wykorzystuje Go int64do intna GOARCH amd64 i int32dla int32-bitowych GOARCHes. Przynajmniej w przypadku domyślnego kompilatora nie jestem pewien co do gccgo. Zatem „ intmoże być większe niż 32-bitowe…” to nie tylko spekulacje, jest raczej prawdopodobne, ponieważ 64-bitowe cele kompilacji są ogólnie uważane za główną gałąź w Go.
LinearZoetrope
12
„W praktyce Go zwykle używa int64 dla int na amd64 [..]” - a dokładniej, int zawsze równa się rozmiarowi bitowemu procesora . Tak więc w systemach 64-bitowych jest 64-bitowy, w systemach 32-bitowych jest to 32-bitowy. Lubię myśleć, że jest to alias int32 lub int64 w zależności od celu kompilacji (nawet jeśli nie jest zaimplementowany jako alias, nie ma znaczenia).
zupa
@zupa jakie jest źródło / odniesienie dla „int zawsze równa się rozmiarowi bitu procesora”?
kapad
29

Pakiet strconv

func ParseInt

func ParseInt(s string, base int, bitSize int) (i int64, err error)

ParseInt interpretuje ciąg s w danej bazie (od 2 do 36) i zwraca odpowiednią wartość i. Jeśli podstawa == 0, podstawa jest implikowana przez prefiks ciągu: podstawa 16 dla „0x”, podstawa 8 dla „0”, a podstawa 10 w innym przypadku.

Argument bitSize określa typ liczby całkowitej, do której musi pasować wynik. Rozmiary bitów 0, 8, 16, 32 i 64 odpowiadają int, int8, int16, int32 i int64.

Błędy zwracane przez ParseInt mają konkretny typ * NumError i zawierają err.Num = s. Jeśli s jest puste lub zawiera nieprawidłowe cyfry, err.Err = ErrSyntax; jeśli wartość odpowiadająca s nie może być reprezentowana przez liczbę całkowitą ze znakiem podanego rozmiaru, err.Err = ErrRange.

ParseIntzawsze zwraca int64wartość. W zależności od bitSizetej wartości będzie pasować do int, int8, int16, int32, lub int64. Jeśli wartość nie może być reprezentowana przez liczbę całkowitą ze znakiem o rozmiarze podanym przez bitSize, to err.Err = ErrRange.

Specyfikacja języka programowania Go

Typy liczbowe

Wartość n-bitowej liczby całkowitej ma szerokość n bitów i jest reprezentowana za pomocą arytmetyki uzupełnień do dwóch.

int8        the set of all signed  8-bit integers (-128 to 127)
int16       the set of all signed 16-bit integers (-32768 to 32767)
int32       the set of all signed 32-bit integers (-2147483648 to 2147483647)
int64       the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)

Istnieje również zestaw wstępnie zadeklarowanych typów liczbowych o rozmiarach właściwych dla implementacji:

uint     either 32 or 64 bits
int      same size as uint

intjest 32- lub 64-bitowy, w zależności od implementacji. Zwykle jest to 32 bity dla kompilatorów 32-bitowych i 64 bity dla kompilatorów 64-bitowych.

Aby sprawdzić rozmiar intlub uint, użyj strconv.IntSize.

Pakiet strconv

Stałe

const IntSize = intSize

IntSizeto rozmiar w bitach wartości intlub uint.

Na przykład,

package main

import (
    "fmt"
    "runtime"
    "strconv"
)

func main() {
    fmt.Println(runtime.Compiler, runtime.GOARCH, runtime.GOOS)
    fmt.Println(strconv.IntSize)
}

Wynik:

gc amd64 linux
64
peterSO
źródło
7

strconv.ParseInti przyjaciele zwracają wersje 64-bitowe, aby interfejs API był czysty i prosty. W przeciwnym razie należałoby utworzyć oddzielne wersje dla każdego możliwego typu zwracanego. Lub powrót interface{}, który następnie musiałby przejść przez potwierdzenie typu. Żadne z nich nie jest idealne.

int64jest wybrany, ponieważ może pomieścić dowolną liczbę całkowitą do obsługiwanych 64-bitów włącznie. Rozmiar bitu, który przekazujesz do funkcji, zapewnia, że ​​wartość jest prawidłowo zamocowana w odpowiednim zakresie. Możesz więc po prostu wykonać konwersję typu na zwróconej wartości, aby przekształcić ją w dowolny typ liczby całkowitej, którego potrzebujesz.

Jeśli chodzi o różnicę między inti int64, jest to zależne od architektury. intjest po prostu aliasem dla 32-bitowej lub 64-bitowej liczby całkowitej, w zależności od architektury, dla której kompilujesz.

Dla wnikliwego oka: zwracana wartość jest liczbą całkowitą ze znakiem. Istnieje oddzielna strconv.ParseUintfunkcja dla liczb całkowitych bez znaku, która zwraca uint64i stosuje to samo rozumowanie, jak wyjaśniono powyżej.

jimt
źródło
4
Z tego, co widziałem do tej pory, jest to prawie poprawne, z wyjątkiem tego, że nie uważam, że intjest to po prostu alias - w rzeczywistości jest to odrębny typ. golang.org/pkg/builtin/#int
Isaac Dontje Lindell
W rzeczy samej. Go tak naprawdę nie wykonuje aliasingu typu. Coś takiego type int int32należy traktować jako jedyny i odrębny typ. Przede wszystkim dlatego, że umożliwia zdefiniowanie nowej funkcjonalności dla inttypu poprzez zastosowanie nowych metod.
jimt
5

strconv.Atoi()Myślę, że dla twoich celów byłoby wygodniej.

Inne odpowiedzi były dość wyczerpujące, jeśli chodzi o wyjaśnienie inttypu, ale myślę, że link do specyfikacji języka Go jest zasługujący na to: http://golang.org/ref/spec#Numeric_types

Matt
źródło
0

W języku Go lang każdy typ jest traktowany jako oddzielny typ danych, którego nie można używać zamiennie z typem podstawowym. Na przykład,

type CustomInt64 int64

W powyższej deklaracji CustomInt64 i wbudowany int64 są dwoma oddzielnymi typami danych i nie mogą być używane zamiennie.

To samo dotyczy int, int32 i int64, wszystkie są oddzielnymi typami danych, których nie można używać zamiennie. Gdzie int32 to 32, jego typ całkowity, int64 to 64 bity, a rozmiar ogólnego typu int zależy od platformy. Ma 32 bity szerokości w systemie 32-bitowym i 64 bity w systemie 64-bitowym. Dlatego musimy być ostrożni i konkretni podczas określania ogólnych typów danych, takich jak int, uint i float. Może to spowodować problem w kodzie i spowoduje awarię aplikacji na innej platformie.

Umar Hayat
źródło