Tuplas são uma forma leve de agrupar um conjunto fixo de dados de tipos arbitrários. Uma tupla não tem um nome específico; dar nome a uma estrutura de dados a transforma em uma struct. Os campos de uma tupla não têm nomes; eles são acessados por meio de desestruturação ou por posição.
Tuplas são sempre criadas com uma expressão de tupla:
// pointless but legal
let unit = ();
// single element
let single_element = ("note the comma",);
// two element
let two_element = (123, "elements can be of differing types");
Tuplas podem ter um número arbitrário de elementos.
É possível acessar os elementos de uma tupla por desestruturação. Isso significa apenas atribuir nomes de variáveis aos elementos individuais da tupla, consumindo-a.
let (elem1, _elem2) = two_element;
assert_eq!(elem1, 123);
Também é possível acessar os elementos de uma tupla por índice posicional numérico. A indexação, como sempre, começa em 0.
let notation = single_element.0;
assert_eq!(notation, "note the comma");
Você também vai trabalhar com structs de tupla. Assim como structs normais, elas são tipos nomeados; diferente de structs normais, elas têm campos anônimos. A sintaxe delas é muito parecida com a sintaxe normal de tupla. É legal usar tanto desestruturação quanto acesso posicional.
struct TupleStruct(u8, i32);
let my_tuple_struct = TupleStruct(123, -321);
let neg = my_tuple_struct.1;
let TupleStruct(byte, _) = my_tuple_struct;
assert_eq!(neg, -321);
assert_eq!(byte, 123);
Todos os campos de tuplas anônimas são sempre públicos. No entanto, os campos de structs de tupla têm visibilidade individual, que por padrão é privada, assim como os campos de structs padrão. Você pode tornar os campos públicos com o modificador pub, assim como em uma struct padrão.
// fails due to private fields
mod tuple { pub struct TupleStruct(u8, i32); }
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); }
// succeeds: fields are public
mod tuple { pub struct TupleStruct(pub u8, pub i32); }
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); }
Você está trabalhando em um jogo voltado para um sistema embarcado de baixo consumo e precisa escrever várias funções utilitárias que serão usadas por outras partes do jogo.
O quociente é o resultado de uma divisão.
fn divmod(dividend: i16, divisor: i16) -> (i16, i16)
Exemplo:
assert_eq!(divmod(10, 3), (3, 1));
Isso vai ajudar a viabilizar uma otimização do buffer da tela, promete seu chefe.
Iteradores são itens que expõem os métodos definidos pela trait Iterator. Essa documentação é bastante extensa, porque oferecem muitos métodos; aqui estão as propriedades mais relevantes:
enumerate que retorna uma tupla (i, val) para cada valorfilter que usa uma closure para determinar se deve produzir um elemento do iteradormap que usa uma closure para modificar elementos do iteradorComo sua função pode rodar em qualquer tipo de iterador, ela usa impl para indicar que se trata de uma instância de trait e não de um item simples. Do mesmo modo, a sintaxe <Item=T> significa apenas que não importa que tipo de item o iterador produz; sua função pode produzir os elementos pares de qualquer iterador.
fn evens<T>(iter: impl Iterator<Item=T>) -> impl Iterator<Item=T>
Exemplos:
let mut even_ints = evens(0_u8..);
assert_eq!(even_ints.next(), Some(0));
assert_eq!(even_ints.next(), Some(2));
assert_eq!(even_ints.next(), Some(4));
assert_eq!(even_ints.next(), Some(6));
let mut evens_from_odds = evens(1_i16..);
assert_eq!(evens_from_odds.next(), Some(1));
assert_eq!(evens_from_odds.next(), Some(3));
assert_eq!(evens_from_odds.next(), Some(5));
assert_eq!(evens_from_odds.next(), Some(7));
Para facilitar o mapeamento, você tem uma struct de tupla Position:
struct Position(i16, i16);
Você precisa implementar um método manhattan em Position que retorna a distância de Manhattan dessa posição até a origem (Position(0, 0)).
impl Position {
fn manhattan(&self) -> i16
}
Exemplo:
assert_eq!(Position(3, 4).manhattan(), 7);
Crie sua conta no Exercism para aprender e dominar Rust com 99 exercícios e mentoria humana de verdade, tudo de graça.