¿Cuál es la diferencia entre int e int64 en Go?

86

Tengo una cadena que contiene un número entero (que se ha leído de un archivo).

Estoy tratando de convertir el stringa un intusing strconv.ParseInt(). ParseIntrequiere que proporcione un tamaño de bits (los tamaños de bits 0, 8, 16, 32 y 64 corresponden a int, int8, int16, int32 e int64).

El entero leído del archivo es pequeño (es decir, debería caber en un int normal). Sin embargo, si paso un tamaño de bits de 0, obtengo un resultado de tipo int64(presumiblemente porque estoy ejecutando un sistema operativo de 64 bits).

¿Por qué está pasando esto? ¿Cómo obtengo un int normal? (Si alguien tiene una introducción rápida sobre cuándo y por qué debería usar los diferentes tipos de int, ¡sería increíble!)

Editar: puedo convertir el int64 a un int normal usando int([i64_var]). Pero todavía no entiendo por qué ParseInt()me da un int64 cuando solicito un tamaño de bits de 0.

Isaac Dontje Lindell
fuente
2
¿Utiliza Atoi por brevedad? Además, ¿su función ParseInt devuelve un error?
Matt
2
Bien, ahora estoy un poco confundido. Si uso Atoi (), me da un int y todo funciona. Estaba llamando parseInt(s, 0, 0), lo que debería inferir base10 (ya que la cadena no tiene un prefijo base). Sin embargo, Atoi es una forma abreviada de llamar parseIntcon una base de 10. ¿Por qué el parámetro base hace una diferencia en el tipo devuelto?
Isaac Dontje Lindell
El parámetro base determina cómo se lee la cadena de entrada. Una cadena puede verse como "123" o "0xBEEFCAKE" o "1011101" o "0677". Todos los cuales tienen un significado diferente y producen un valor numérico diferente. Un valor base de 0significa que el código intenta resolver esto por sí mismo. Pero a veces esto no es posible. 11(decimal) vs 11(binario) representan valores completamente diferentes.
jimt
1
Bien, supongo que lo que realmente me confunde son los documentos. Los documentos de Atoi solo dicen que es solo una "abreviatura de parseInt(s, 10, 0)". Pero, ¿por qué entonces Atoi regresa intmientras parseIntregresa int64?
Isaac Dontje Lindell
1
Sin saber exactamente por qué, asumiré que Atoise agregó simplemente para adaptarse a las personas que están más familiarizadas con la API de C:int atoi ( const char * str );
jimt

Respuestas:

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

ParseInt siempre regresa int64

bitSizedefine rango de valores. Si el valor correspondiente as no puede ser representado por un entero con signo del tamaño dado, err.Err = ErrRange.

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

type int int

int es un tipo entero con signo que tiene al menos 32 bits de tamaño. Sin embargo, es un tipo distinto y no un alias para, digamos, int32.

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

Por intlo tanto, podría ser mayor que 32 bits en el futuro o en algunos sistemas como intC.

Supongo que en algunos sistemas int64puede ser más rápido int32porque ese sistema solo funciona con enteros de 64 bits.

Aquí hay un ejemplo de error cuando bitSizees 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
fuente
22
En la práctica, Go generalmente usa int64for inten un GOARCH amd64 y int32para inten GOARCH de 32 bits. Al menos con el compilador predeterminado, no estoy seguro de gccgo. Entonces, " intpodría ser mayor que 32 bits ..." no es solo una especulación, en realidad es bastante probable ya que los objetivos de compilación de 64 bits generalmente se consideran la rama principal en Go.
LinearZoetrope
12
"En la práctica, Go generalmente usa int64 para int en un amd64 [..]" - más precisamente, int siempre es igual al tamaño de bits del procesador . Entonces, en sistemas de 64 bits, es de 64 bits, en sistemas de 32 bits, es de 32 bits. Me gusta pensar que es un alias de int32 o int64 dependiendo de su objetivo de compilación (incluso si no está implementado como un alias, no importa).
zupa
@zupa ¿cuál es la fuente / referencia para "int siempre es igual al tamaño de bits del procesador"?
Kapad
29

Paquete strconv

func ParseInt

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

ParseInt interpreta una cadena s en la base dada (2 a 36) y devuelve el valor correspondiente i. Si base == 0, la base está implícita en el prefijo de la cadena: base 16 para "0x", base 8 para "0" y base 10 en caso contrario.

El argumento bitSize especifica el tipo de entero en el que debe encajar el resultado. Los tamaños de bit 0, 8, 16, 32 y 64 corresponden a int, int8, int16, int32 e int64.

Los errores que devuelve ParseInt tienen un tipo concreto * NumError e incluyen err.Num = s. Si s está vacío o contiene dígitos no válidos, err.Err = ErrSyntax; si el valor correspondiente as no puede ser representado por un entero con signo del tamaño dado, err.Err = ErrRange.

ParseIntsiempre devuelve un int64valor. En función de bitSizeeste valor se ajusta a int, int8, int16, int32, o int64. Si el valor no puede ser representado por un entero con signo del tamaño dado por bitSize, entonces err.Err = ErrRange.

La especificación del lenguaje de programación Go

Tipos numéricos

El valor de un entero de n bits tiene un ancho de n bits y se representa mediante aritmética en complemento a dos.

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)

También hay un conjunto de tipos numéricos predeclarados con tamaños específicos de implementación:

uint     either 32 or 64 bits
int      same size as uint

intes de 32 o 64 bits, según la implementación. Por lo general, es de 32 bits para compiladores de 32 bits y de 64 bits para compiladores de 64 bits.

Para averiguar el tamaño de un into uint, utilice strconv.IntSize.

Paquete strconv

Constantes

const IntSize = intSize

IntSizees el tamaño en bits de un valor into uint.

Por ejemplo,

package main

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

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

Salida:

gc amd64 linux
64
peterSO
fuente
7

strconv.ParseInty sus amigos regresan versiones de 64 bits para mantener la API limpia y simple. De lo contrario, habría que crear versiones independientes para cada posible tipo de devolución. O return interface{}, que luego tendría que pasar por una aserción de tipo. Ninguno de los cuales es ideal.

int64se elige porque puede contener cualquier tamaño de entero hasta, inclusive, los 64 bits admitidos. El tamaño de bit que pasa a la función garantiza que el valor se fije correctamente en el rango correcto. Entonces, simplemente puede hacer una conversión de tipo en el valor devuelto, para convertirlo en cualquier tipo de entero que necesite.

En cuanto a la diferencia entre inty int64, esto depende de la arquitectura. intes simplemente un alias para un entero de 32 bits o de 64 bits, según la arquitectura para la que está compilando.

Para el ojo perspicaz: el valor devuelto es un entero con signo. Hay una strconv.ParseUintfunción separada para enteros sin signo, que devuelve uint64y sigue el mismo razonamiento que se explicó anteriormente.

Jimt
fuente
4
Por lo que he visto hasta ahora, esto es casi correcto, excepto que no creo que intsea ​​simplemente un alias, de hecho es un tipo distinto. golang.org/pkg/builtin/#int
Isaac Dontje Lindell
En efecto. Go realmente no hace alias de tipo. Algo parecido type int int32debe tratarse como un tipo único y separado. Sobre todo porque permite definir nuevas funcionalidades para el inttipo mediante la aplicación de nuevos métodos.
jimt
0

En Go lang, cada tipo se considera un tipo de datos independiente que no se puede utilizar indistintamente con el tipo base. Por ejemplo,

type CustomInt64 int64

En la declaración anterior, CustomInt64 e int64 integrado son dos tipos de datos separados y no se pueden usar indistintamente.

Lo mismo ocurre con int, int32 e int64, todos estos son tipos de datos separados que no se pueden usar indistintamente. Donde int32 es 32 su tipo entero, int64 es 64 bits y el tamaño del tipo int genérico depende de la plataforma. Tiene 32 bits de ancho en un sistema de 32 bits y 64 bits de ancho en un sistema de 64 bits. Por lo tanto, debemos ser cuidadosos y específicos al especificar tipos de datos genéricos como int, uint y float. Puede causar un problema en algún lugar del código y bloquear la aplicación en una plataforma diferente.

Umar Hayat
fuente