Qual é a diferença entre int e int64 em Go?

86

Eu tenho uma string contendo um inteiro (que foi lido de um arquivo).

Estou tentando converter stringpara intusando strconv.ParseInt(). ParseIntrequer que eu forneça um tamanho de bits (tamanhos de bits 0, 8, 16, 32 e 64 correspondem a int, int8, int16, int32 e int64).

O inteiro lido do arquivo é pequeno (ou seja, deve caber em um int normal). Se eu passar um tamanho de bits de 0, porém, obtenho um resultado do tipo int64(provavelmente porque estou executando em um sistema operacional de 64 bits).

Por que isso está acontecendo? Como faço para obter um int normal? (Se alguém tiver uma introdução rápida sobre quando e por que devo usar os diferentes tipos de int, seria incrível!)

Edit: posso converter o int64 em um int normal usando int([i64_var]). Mas ainda não entendo por que ParseInt()está me dando um int64 quando estou solicitando um tamanho de bits igual a 0.

Isaac Dontje Lindell
fonte
2
Use Atoi para brevidade? Além disso, a função ParseInt está retornando um erro?
Matt
2
Ok, agora estou um pouco confuso. Se eu usar Atoi (), ele me dá um int e tudo funciona. Eu estava chamando parseInt(s, 0, 0), o que deve inferir base10 (já que a string não tem um prefixo de base). No entanto, Atoi é uma abreviação para chamar parseIntcom uma base de 10. Por que o parâmetro base faz diferença no tipo retornado?
Isaac Dontje Lindell
O parâmetro base determina como a string de entrada é lida. Uma string pode ser semelhante a "123" ou "0xBEEFCAKE" ou "1011101" ou "0677". Todos eles têm um significado diferente e geram um valor numérico diferente. Um valor base de 0significa que o código tenta descobrir isso sozinho. Mas às vezes isso não é possível. 11(decimal) vs 11(binário) representam valores totalmente diferentes.
jimt
1
Ok, acho que estou realmente confuso sobre os documentos. Os documentos para Atoi dizem apenas que é apenas uma "abreviação de parseInt(s, 10, 0)". Mas por que então Atoi retorna intenquanto parseIntretorna int64?
Isaac Dontje Lindell
1
Não sabendo exatamente o motivo, assumirei que Atoifoi adicionado simplesmente para acomodar as pessoas que estão mais familiarizadas com a API C:int atoi ( const char * str );
jimt

Respostas:

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

ParseInt sempre retorna int64

bitSizedefine faixa de valores. Se o valor correspondente a s não puder ser representado por um inteiro com sinal do tamanho fornecido, err.Err = ErrRange.

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

type int int

int é um tipo inteiro assinado com pelo menos 32 bits de tamanho. É um tipo distinto, no entanto, e não um alias para, digamos, int32.

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

Portanto, intpode ser maior do que 32 bits no futuro ou em alguns sistemas como o intC.

Acho que em alguns sistemas int64pode ser mais rápido do que int32porque esse sistema só funciona com inteiros de 64 bits.

Aqui está um exemplo de erro quando bitSizeé 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
fonte
22
Na prática, Go geralmente usa int64para intem um GOARCH amd64 e int32para intem GOARCHes de 32 bits. Pelo menos com o compilador padrão, não tenho certeza sobre o gccgo. Portanto, " intpode ser maior que 32 bits ..." não é apenas especulação, é na verdade bastante provável, já que os destinos de compilação de 64 bits são geralmente considerados o ramo principal do Go.
LinearZoetrope de
12
"Na prática, Go geralmente usa int64 para int em um amd64 [..]" - mais precisamente, int sempre é igual ao tamanho de bits do processador . Então, em sistemas de 64 bits, é de 64 bits, em sistemas de 32 bits, é de 32 bits. Gosto de pensar que é um alias de int32 ou int64, dependendo do seu destino de compilação (mesmo que não seja implementado como um alias, não importa).
zupa
@zupa qual é a fonte / referência para "int sempre igual ao tamanho de bits do processador"?
kapad
29

Pacote strconv

func ParseInt

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

ParseInt interpreta uma string s na base fornecida (2 a 36) e retorna o valor i correspondente. Se base == 0, a base está implícita no prefixo da string: base 16 para "0x", base 8 para "0" e base 10 caso contrário.

O argumento bitSize especifica o tipo inteiro no qual o resultado deve se ajustar. Os tamanhos de bits 0, 8, 16, 32 e 64 correspondem a int, int8, int16, int32 e int64.

Os erros que ParseInt retorna têm tipo concreto * NumError e incluem err.Num = s. Se s estiver vazio ou contiver dígitos inválidos, err.Err = ErrSyntax; se o valor correspondente a s não puder ser representado por um inteiro com sinal do tamanho fornecido, err.Err = ErrRange.

ParseIntsempre retorna um int64valor. Dependendo bitSize, este valor vai se encaixar int, int8, int16, int32, ou int64. Se o valor não puder ser representado por um inteiro com sinal do tamanho fornecido por bitSize, então err.Err = ErrRange.

A especificação da linguagem de programação Go

Tipos numéricos

O valor de um inteiro de n bits tem largura de n bits e é representado usando aritmética de complemento de dois.

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)

Também há um conjunto de tipos numéricos pré-declarados com tamanhos específicos de implementação:

uint     either 32 or 64 bits
int      same size as uint

inté de 32 ou 64 bits, dependendo da implementação. Normalmente é de 32 bits para compiladores de 32 bits e 64 bits para compiladores de 64 bits.

Para descobrir o tamanho de um intou uint, use strconv.IntSize.

Pacote strconv

Constantes

const IntSize = intSize

IntSizeé o tamanho em bits de um valor intou uint.

Por exemplo,

package main

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

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

Resultado:

gc amd64 linux
64
PeterSO
fonte
7

strconv.ParseInte amigos retornam versões de 64 bits para manter a API limpa e simples. Caso contrário, seria necessário criar versões separadas para cada tipo de retorno possível. Ou return interface{}, que então teria que passar por uma declaração de tipo. Nenhum dos quais é ideal.

int64é escolhido porque pode conter qualquer tamanho de inteiro até, e incluindo, os 64 bits suportados. O tamanho do bit que você passa para a função garante que o valor seja fixado corretamente no intervalo correto. Portanto, você pode simplesmente fazer uma conversão de tipo no valor retornado, para transformá-lo em qualquer tipo de inteiro que você precisar.

Quanto à diferença entre inte int64, isso depende da arquitetura. inté simplesmente um alias para um inteiro de 32 ou 64 bits, dependendo da arquitetura para a qual você está compilando.

Para o olho mais perspicaz: O valor retornado é um número inteiro com sinal. Há uma strconv.ParseUintfunção separada para inteiros sem sinal, que retorna uint64e segue o mesmo raciocínio explicado acima.

Jimt
fonte
4
Pelo que vi até agora, isso é quase correto, exceto que não acho que intseja simplesmente um pseudônimo - é na verdade um tipo distinto. golang.org/pkg/builtin/#int
Isaac Dontje Lindell
De fato. Go realmente não faz aliasing de tipo. Algo semelhante type int int32deve ser tratado como um tipo único e separado. Notavelmente porque permite que novas funcionalidades sejam definidas para o inttipo por meio da aplicação de novos métodos.
jimt
5

Para seus propósitos, strconv.Atoi()seria mais conveniente, eu acho.

As outras respostas foram bem exaustivas sobre a explicação do inttipo, mas acho que um link para a especificação da linguagem Go é merecido aqui: http://golang.org/ref/spec#Numeric_types

Matt
fonte
0

No Go lang, cada tipo é considerado um tipo de dados separado que não pode ser usado de forma intercambiável com o tipo base. Por exemplo,

type CustomInt64 int64

Na declaração acima, CustomInt64 e interno int64 são dois tipos de dados separados e não podem ser usados ​​de forma intercambiável.

O mesmo é o caso com int, int32 e int64, todos esses são tipos de dados separados que não podem ser usados ​​de forma intercambiável. Onde int32 é 32 seu tipo inteiro, int64 é 64 bits e o tamanho do tipo genérico int depende da plataforma. Tem 32 bits de largura em um sistema de 32 bits e 64 bits de largura em um sistema de 64 bits. Portanto, devemos ser cuidadosos e específicos ao especificar tipos de dados genéricos como int, uint e float. Isso pode causar um problema em algum lugar do código e travará o aplicativo em uma plataforma diferente.

Umar Hayat
fonte