Contents

Rust - Tipos

Declaração de variáveis e tipo de dados

RUST é uma linguagem que “tipada”. Isso significa que o compilador tem a necessidade de saber qual o tipo da variável que você esta declarando no seu código durante a compilação.

1
2
3
4
fn main() {
    let mut my_int: i32 = -7;
    let mut my_u_int: u32 = 7;
}

No código acima declaramos duas variáveis. A primeira ‘my_int’ que é do tipo inteiro e a segunda ‘my_u_int’ que é do tipo ‘inteiro sem sinal’ e nesse caso estamos deixando claro para o compilador que ‘my_int’ deve receber somente dados do tipo inteiro e que ‘my_u_int’ deve receber somente dados do tipo inteiro e positivo. Qualquer tentativa de atribuir um valor fora dessa regra ira gerar um erro de compilação.

Mas espera um minuto! Nos códigos anteriores lembro de estar declarando variáveis sem especificar o tipo da variável para o compilador.

1
2
3
fn main() {
    let my_var = 5;
}

O código acima funciona pois o compilador possuí a capacidade de prever o tipo de dado que você esta atribuindo para essa variável. O compilador sabe que ‘5’ é do tipo inteiro e portanto ‘my_var’ é do tipo ‘i32’

Então porque não eu deveria dizer ao compilador qual o tipo de variável eu vou guardar naquele endereço de memória se ele pode adivinhar? A necessidade de ser claro sobre o tipo guardado em uma variável vem quando estamos trabalhando com algum tipo de conversão de dados como no exemplo abaixo:

1
2
3
4
fn main() {
    let my_var = "7".parse().expect("Not a Number");         // Linha 1
    let my_second_var = "7a".parse().expect("Not a Number"); // Linha 2
}

No exemplo acima estamos tentando converter uma string em um número e essa conversão pode retornar um número em caso de sucesso ou algo diferente em caso de falha. Em situações como essa o compilador não possuí nenhuma maneira de saber qual é o tipo de variável você quer trabalhar e portanto irá lhe gerar um erro de compilação. Casos assim podem acontecer por exemplo em uma variável que guarda um dado inserido pelo usuário através da linha de comando.

Uma outra razão para ser explícito na declaração de variáveis enquanto ao seu tipo é a ideia de que ser mais claro irá ajudar novos programadores ou até mesmo você a entender o código no futuro.

Tipos escalares (Scalar Types)

Tipos escalares são representados por um valor único e RUST tem 4 ‘scalar types’

  • Integers (Inteiros)
  • Floating-point Numbers (Pontos flutuantes)
  • Booleans (Boleanos)
  • Characters (Caracteres)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
fn main() {

    // --- INTEIROS

    let int_8 : i8 = 1;        // -128 a 127
    let int_16: i16 = 1;       // -32,768 a 32,677
    let int_32: i32 = 1;       // -2,147,483,648 a 2,147,483,647
    let int_64: i64 = 1;       // -9,223,372,036,854,775,808 a 9,223,372,036,854,775,807
    let int_arch: isize = 1;   // Depende da arquitetura do seu processador

    let u_int_8: u8 = 1;       // 0 a 255
    let u_int_16: u16 = 1;     // 0 a 65,535
    let u_int_32: u32 = 1;     // 0 a 4,294,967,295
    let u_int_64: u64 = 1;     // 0 a 18,446,744,073,709,551,615
    let u_int_arch: usize = 1; // Depende da arquitetura do seu processador

    // --- PONTOS FLUTUANTES

    let f_32: f32 = 1.0; // Ponto flutuante
    let f_64: f64 = 1.0; // Ponto flutuante

    // --- BOLEANOS

    let b: bool = true; // Boleano

    // --- CARACTERES

    let c: char = 'a'; // Caractere
}

Tipo composto (Compound type)

Tipos compostos é uma forma de agrupar múltiplos valores em um tipo e o RUST possuí dois tipos primitivos de tipos compostos. São eles:

  • Tuplas (Tuples)
  • Matriz (Array)

Tupla (Tuple)

A tupla é uma forma que temos de agrupar dados de diferente tipos de dado. É um tipo composto.

No exemplo abaixo criamos uma tupla que guarda um inteiro de 32 bits, um número flutuante de precisão dupla e um número inteiro sem sinal de 8 bits

1
2
3
fn main() {
    let tup: (i32, f64, u8) = (500, 6.4, 1);
}

E podemos então acessar cada valor individualmente.

No RUST temos algumas formas para acessar cada valor:

1
2
3
4
5
6
7
fn main() {
    let tup: (i32, f64, u8) = (500, 6.4, 1); // Linha 1
    let (x, y, z) = tup;                     // Linha 2
    let a = tup.0;                           // Linha 3
    let b = tup.1;                           // Linha 4
    let c = tup.2;                           // Linha 5
}

Linha 1 criamos uma nova variável do tipo ‘Tuple’ Linha 2 temos x = 500, y = 6.4 e z = 1 Linha 3 temos a = 500 Linha 4 temos b = 6.4 Linha 5 temos c = 1

É interessante observar que na ‘Linha 2’ usamos uma técnica chamada de ‘destructing’ a qual vamos estudar mais a frente.

Já na ‘Linha 3’ até a ‘Linha 5’ estamos acessando o índice da variável dentro da nossa tupla onde o índice 0 possuí um valor do tipo ‘i32’, o índice 1 possuí um valor do tipo ‘f64’ e índice 2 possuí um valor do tipo ‘u8’

Matrizes (Array)

Uma matriz (array) é um conjunto de valores organizados em linhas e colunas. Matrizes só podem guardar valores do mesmo tipo.

Em RUST assim que você declara uma nova matriz (array) esse não pode mais ter ser tamanho alterado.

A vantagem de se trabalhar com um array é de que sua alocação é rápida e feita na região de ‘stack’ da sua aplicação. Entre as vantagens de se ter um dado na ‘stack’ é a velocidade de acesso. Outra vantagem de um array é que, quando se conhece a posição de um dado neste array, o acesso ao dado é instantâneo. A desvantagem de se trabalhar com um array é que muitas vezes não sabemos a quantidade de dados com os quais estamos lidando e devido a regra de que não podemos alterar o valor de um array já declarado podemos acabar com um array muito pequeno ou muito grande.

Um exemplo de quando o Array é útil:

1
2
3
4
fn main() {
    let semana = ["Segunda", "Terca", "Quarta", "Quinta", "Sexta", "Sabado",
    "Domingo"];
}

Um problema de se trabalhar com Arrays em algumas linguagens é a liberdade de acessar uma posição não válida o que leva a um comportamento não esperado ou o ‘crash’ de uma aplicação.

Nosso Array do exemplo acima é um Array de 7 elementos e se tentamos acessar qualquer posição que não esteja entre 0 e 6 o RUST já nos informa com um erro de compilação.

1
2
3
4
5
6
fn main() {
    let semana = ["Segunda", "Terca", "Quarta", "Quinta", "Sexta", "Sabado",
    "Domingo"];
    let my_data_a = semana[0];  // Linha 1
    let my_data_b = semana[20]; // Linha 2
}

A ‘linha 1’ do exemplo acima nos retornaria o valor “Segunda” mas como a ‘Linha 2’ esta acessando uma região inválida no nosso array de 7 elementos o RUST vai gerar um erro de compilação e seu aplicativo não vai rodar até que você corrija este erro.