В чем разница между int и int64 в Go?

86

У меня есть строка, содержащая целое число (которое было прочитано из файла).

Я пытаюсь преобразовать stringфайл intusing strconv.ParseInt(). ParseIntтребует, чтобы я указал размер в битах (размеры битов 0, 8, 16, 32 и 64 соответствуют int, int8, int16, int32 и int64).

Целое число, прочитанное из файла, невелико (то есть должно соответствовать обычному int). Однако, если я передаю битовый размер 0, я получаю результат типа int64(предположительно, потому что я работаю в 64-битной ОС).

Почему это происходит? Как мне просто получить нормальный int? (Если у кого-то есть краткое руководство о том, когда и почему мне следует использовать разные типы int, это было бы здорово!)

Изменить: я могу преобразовать int64 в обычный int, используя int([i64_var]). Но я до сих пор не понимаю, почему ParseInt()мне предоставляется int64, когда я запрашиваю битовый размер 0.

Исаак Донтье Линделл
источник
2
Используйте Atoi для краткости? Кроме того, ваша функция ParseInt возвращает ошибку?
Мэтт
2
Хорошо, теперь я немного запутался. Если я использую Atoi (), он дает мне int, и все работает. Я звонил parseInt(s, 0, 0), что должно означать base10 (поскольку строка не имеет префикса base). Однако Atoi - это сокращение для вызова parseIntс базой , равной 10. Почему базовый параметр влияет на возвращаемый тип?
Исаак Донтье Линделл
Базовый параметр определяет, как считывается входная строка. Строка может выглядеть как «123», «0xBEEFCAKE», «1011101» или «0677». Все они имеют разное значение и дают разное числовое значение. Базовое значение 0означает, что код пытается выяснить это самостоятельно. Но иногда это невозможно. 11(десятичный) vs 11(двоичный) представляют собой совершенно разные значения.
jimt
1
Ладно, думаю, что меня действительно смущает, так это документы. В документации для Atoi сказано только, что это просто сокращение для parseInt(s, 10, 0). Но почему тогда Atoi возвращается, intа parseIntвозвращает int64?
Исаак Донтье Линделл
1
Не зная точно, почему, я предполагаю, что это Atoiбыло добавлено просто для удобства людей, более знакомых с C API:int atoi ( const char * str );
jimt

Ответы:

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

ParseInt всегда возвращает int64

bitSizeопределяет диапазон значений. Если значение, соответствующее s, не может быть представлено целым числом со знаком заданного размера, err.Err = ErrRange.

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

type int int

int - это целочисленный тип со знаком, который имеет размер не менее 32 бита. Однако это отдельный тип, а не псевдоним, скажем, для int32.

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

Так intчто в будущем может быть больше 32 бит или в некоторых системах, таких как intC.

Я предполагаю, что в некоторых системах int64может быть быстрее, int32потому что эта система работает только с 64-битными целыми числами.

Вот пример ошибки при bitSize8

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

package main

import (
    "fmt"
    "strconv"
)

func main() {
    i, err := strconv.ParseInt("123456", 10, 8)
    fmt.Println(i, err)
}
Сюрикен
источник
22
На практике Go обычно использует int64for intна amd64 GOARCH и int32for intна 32-битных GOARCH. По крайней мере, с компилятором по умолчанию я не уверен насчет gccgo. Так что « intможет быть больше 32 бит ...» - это не просто предположение, это на самом деле весьма вероятно, поскольку 64-битные цели компиляции обычно считаются основной веткой в ​​Go.
LinearZoetrope 01
12
«На практике Go обычно использует int64 вместо int на amd64 [..]» - точнее, int всегда равняется разрядности процессора . Итак, в 64-битных системах это 64-битная версия, в 32-битных - 32-битная. Мне нравится думать, что это либо псевдоним int32, либо int64 в зависимости от вашей цели компиляции (даже если он не реализован как псевдоним, не имеет значения).
zupa
@zupa каков источник / ссылка на "int всегда равняется разрядности процессора"?
Капад
29

Пакет strconv

func ParseInt

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

ParseInt интерпретирует строку s в заданной базе (от 2 до 36) и возвращает соответствующее значение i. Если base == 0, база подразумевается префиксом строки: база 16 для «0x», база 8 для «0» и база 10 в противном случае.

Аргумент bitSize указывает целочисленный тип, которому должен соответствовать результат. Разрядность 0, 8, 16, 32 и 64 соответствует int, int8, int16, int32 и int64.

Ошибки, которые возвращает ParseInt, имеют конкретный тип * NumError и включают err.Num = s. Если s пусто или содержит недопустимые цифры, err.Err = ErrSyntax; если значение, соответствующее s, не может быть представлено целым числом со знаком заданного размера, err.Err = ErrRange.

ParseIntвсегда возвращает int64значение. В зависимости от того bitSize, это значение будет вписываться в int, int8, int16, int32, или int64. Если значение не может быть представлено целым числом со знаком размера, заданного bitSize, то err.Err = ErrRange.

Спецификация языка программирования Go

Числовые типы

Значение n-битового целого числа имеет ширину n бит и представлено с использованием арифметики с дополнением до двух.

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)

Существует также набор заранее объявленных числовых типов с размерами, зависящими от реализации:

uint     either 32 or 64 bits
int      same size as uint

intсоставляет 32 или 64 бита, в зависимости от реализации. Обычно это 32 бита для 32-битных компиляторов и 64 бита для 64-битных компиляторов.

Чтобы узнать размер intили uint, используйте strconv.IntSize.

Пакет strconv

Константы

const IntSize = intSize

IntSize- размер в битах значения intили uint.

Например,

package main

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

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

Выход:

gc amd64 linux
64
Питер
источник
7

strconv.ParseIntи друзья возвращают 64-битные версии, чтобы API был чистым и простым. В противном случае пришлось бы создавать отдельные версии для каждого возможного типа возврата. Или return interface{}, который затем должен будет пройти утверждение типа. Ни один из них не идеален.

int64выбран, потому что он может содержать любое целое число до поддерживаемых 64 бит включительно. Размер в битах, который вы передаете в функцию, гарантирует, что значение будет правильно зафиксировано в правильном диапазоне. Таким образом, вы можете просто преобразовать тип возвращаемого значения, чтобы преобразовать его в любой требуемый целочисленный тип.

Что касается разницы между intи int64, это зависит от архитектуры. int- это просто псевдоним для 32-битного или 64-битного целого числа, в зависимости от архитектуры, для которой вы компилируете.

Для проницательного взгляда: возвращаемое значение - целое число со знаком. Для strconv.ParseUintцелых чисел без знака существует отдельная функция, которая возвращает uint64и следует тем же рассуждениям, что и объяснено выше.

удар
источник
4
Из того, что я видел до сих пор, это почти правильно, за исключением того, что я не думаю, что intэто просто псевдоним - это на самом деле отдельный тип. golang.org/pkg/builtin/#int
Исаак Донтье Линделл
На самом деле. Go на самом деле не использует псевдонимы типов. Что-то подобное type int int32следует рассматривать как уникальный и отдельный тип. В частности, потому, что он позволяет определять новые функции для intтипа посредством применения новых методов.
jimt 01
5

strconv.Atoi()Думаю, для ваших целей было бы удобнее.

Другие ответы были довольно исчерпывающими по поводу объяснения intтипа, но я думаю, что ссылка на спецификацию языка Go заслуживает здесь: http://golang.org/ref/spec#Numeric_types

Мэтт
источник
0

В языке Go каждый тип рассматривается как отдельный тип данных, который не может использоваться взаимозаменяемо с базовым типом. Например,

type CustomInt64 int64

В приведенном выше объявлении CustomInt64 и встроенный int64 являются двумя отдельными типами данных и не могут использоваться взаимозаменяемо.

То же самое и с int, int32 и int64, все это отдельные типы данных, которые нельзя использовать взаимозаменяемо. Где int32 - это 32 его целочисленный тип, int64 - 64 бита, а размер общего типа int зависит от платформы. Он имеет ширину 32 бита в 32-битной системе и 64 бита в 64-битной системе. Поэтому мы должны быть осторожны и конкретны при указании общих типов данных, таких как int, uint и float. Это может вызвать проблему где-то в коде и привести к сбою приложения на другой платформе.

Умар Хаят
источник