In

Inteiros em Rust

1 exercício

Sobre Inteiros

Inteiros são números inteiros. Não têm parte fracionária nem decimal. São representados na máquina como um padrão de bits binários.

Inteiros podem ou não ter sinal. Ter sinal significa reservar um dos bits do número para indicar se ele é negativo ou não.

Todos os inteiros têm uma largura de bits, que é simplesmente a quantidade de bits que compõem o número. Isso afeta o valor máximo que aquele tipo inteiro consegue representar.

Por exemplo, um dos tipos inteiros mais comuns é o u8: um inteiro de 8 bits sem sinal. Talvez você reconheça esse tipo como um único byte. Ele tem valor mínimo 0 e valor máximo 255.

Rust tem 12 tipos primitivos de inteiros, divididos por largura de bits e sinal:

Sem sinal Com sinal
u8 i8
u16 i16
u32 i32
u64 i64
u128 i128
usize isize

A largura de bits de um inteiro é sempre indicada pelo número depois do u ou do i. usize e isize são especiais: têm a mesma largura que um ponteiro na máquina de destino. Isso significa que numa arquitetura de 64 bits, usize e isize têm 64 bits de largura, mas numa arquitetura de 32 bits, têm 32 bits de largura.

Qual devo usar?

Em geral, se você só precisa representar algum número, use um i32: 32 bits oferecem uma faixa ampla o suficiente para que um overflow seja relativamente improvável, e números com sinal guardam menos surpresas que números sem sinal. O i32 equivale a um long em C, ou a um int em Java. Se você usar um literal numérico e não anotar o tipo explicitamente, ele vai usar i32 por padrão.

Se você estiver trabalhando com dados binários, o mais fácil é trabalhar com bytes: &[u8] ou Vec<u8>.

Rust usa usize para o tamanho e a indexação de coleções. Isso porque um computador só consegue endereçar, teoricamente, usize::MAX bytes de memória, então não é possível ter coleções em memória maiores que isso. Por isso, usize pode ser útil se você trabalha muito com coleções.

Se os seus dados não couberem num inteiro de 32 bits, considere passar para um inteiro de 64 ou 128 bits. Se os seus dados não couberem num inteiro de 128 bits, você pode usar um tipo de inteiro grande, como o fornecido pelo num-bigint.

Inteiros de 16 bits não são muito comuns, mas podem ser úteis ao visar certos microcontroladores.

Se você sabe que não há casos negativos válidos na sua aplicação, é melhor usar um inteiro sem sinal em vez de um inteiro com sinal. Contar é um bom exemplo disso.

Conversão entre inteiros

Rust não tem conversões numéricas implícitas. Se você precisar converter entre tipos inteiros, existem duas estratégias básicas: a palavra-chave as e os traits From e TryFrom.

Usar a palavra-chave as é simples: expr as Type. No entanto, há uma série de detalhes e sutilezas que você precisa ter em mente ao usar conversões com as.

A conversão baseada em traits é um pouco mais trabalhosa, mas mais segura: os traits de conversão só são implementados onde é seguro. Por exemplo, o i32 implementa From<u8>, From<u16>, From<i8> e From<i16>: qualquer valor representável por qualquer um desses tipos tem garantia de ser representável num i32. Ele pode ser usado como i32::from(expr), ou expr.into(), onde expr é de um desses tipos. O i32 também implementa TryFrom<u32>, TryFrom<u64>, TryFrom<u128>, TryFrom<usize>, TryFrom<i64>, TryFrom<i128> e TryFrom<isize>. Essas conversões vão explicitamente dar certo ou sofrer overflow, dependendo do valor. Para usá-las, você precisará importar os traits std::convert::TryFrom ou std::convert::TryInto conforme o caso, e então usar i32::try_from(expr) ou expr.try_into(), onde expr é de um tipo adequado.

Em geral, é preferível usar a conversão baseada em traits em vez da conversão com as, especialmente ao converter de um tipo mais largo para um mais estreito. A conversão baseada em traits é insignificantemente mais cara que a conversão com as: usar as por motivos de desempenho não vale a pena, a não ser num laço extremamente crítico.

Editar via GitHub O link abre em uma nova janela ou aba