Vector\<T>
Vector<T> é um array crescente com posse sobre T. Ele mantém um buffer no heap que dobra de tamanho sempre que fica cheio: o acesso a elementos é O(1) e push é amortizado O(1). O vector chama diretamente malloc/free do libc e não é gerenciado pelo auto-drop do Glide, portanto você deve liberá-lo explicitamente com free() — combine-o com defer para tornar vazamentos impossíveis.
Importação
Nenhuma importação necessária — Vector<T> é embutido.
A struct
pub struct Vector<T> {
data: *T, // buffer no heap; null enquanto cap == 0
len: i32, // número de elementos inicializados (<= cap)
cap: i32, // tamanho da alocação em elementos (potência de dois quando não-zero)
is_arena: bool, // true quando o buffer foi alocado em arena (caminho do LSP)
}
Todos os quatro campos são privados; interaja com o vector apenas por meio de seus métodos.
Construção
| Função | Assinatura | Descrição |
|---|---|---|
new |
fn new() -> *Vector<T> |
Vector vazio sem alocação. O primeiro push aloca. |
with_cap |
fn with_cap(cap: i32) -> *Vector<T> |
Vector vazio pré-dimensionado para comportar pelo menos cap elementos sem realocar. |
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push(10);
v.push(20);
let w: *Vector<i32> = Vector::with_cap(64);
defer w.free();
for let i: i32 = 0; i < 64; i++ { w.push(i); }
println!(w.len()); // 64
return 0;
}
Acesso a elementos e mutação
| Método | Assinatura | Descrição |
|---|---|---|
push |
fn push(self: *Vector<T>, x: T) |
Adiciona x ao final. Realoca (capacidade dobra) quando cheio; amortizado O(1). |
pop |
fn pop(self: *Vector<T>) -> T |
Remove e retorna o último elemento. Comportamento indefinido se vazio — verifique com is_empty() antes. |
get |
fn get(self: *Vector<T>, i: i32) -> T |
Lê o elemento i. Sem verificação de limites. |
set |
fn set(self: *Vector<T>, i: i32, x: T) |
Substitui o elemento i. Sem verificação de limites. |
first |
fn first(self: *Vector<T>) -> T |
Primeiro elemento. Comportamento indefinido se vazio. |
last |
fn last(self: *Vector<T>) -> T |
Último elemento. Comportamento indefinido se vazio. |
swap |
fn swap(self: *Vector<T>, i: i32, j: i32) |
Troca os elementos nas posições i e j no lugar. |
swap_remove |
fn swap_remove(self: *Vector<T>, i: i32) -> T |
Remove e retorna o elemento i em O(1) trocando-o com o último; reordena os elementos restantes. |
reverse |
fn reverse(self: *Vector<T>) |
Inverte os elementos no lugar. O(n). |
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push(10);
v.push(20);
v.push(30);
println!(v.get(0)); // 10
v.set(1, 99);
println!(v.get(1)); // 99
println!(v.first()); // 10
println!(v.last()); // 30
let last: i32 = v.pop(); // 30
println!(last); // 30
println!(v.len()); // 2
return 0;
}
swap, swap_remove e reverse reorganizam no lugar:
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(10, 20, 30, 40);
v.swap(0, 3); // [40, 20, 30, 10]
let removed: i32 = v.swap_remove(1); // remove 20 -> [40, 10, 30]
println!(removed); // 20
v.reverse(); // [30, 10, 40]
println!(v.first(), v.last()); // 30 40
return 0;
}
Tamanho e tempo de vida
| Método | Assinatura | Descrição |
|---|---|---|
len |
fn len(self: *Vector<T>) -> i32 |
Número de elementos inicializados. |
is_empty |
fn is_empty(self: *Vector<T>) -> bool |
true quando len() == 0. |
truncate |
fn truncate(self: *Vector<T>, n: i32) |
Encurta para no máximo n elementos. Sem efeito se já for mais curto; a capacidade não é reduzida. |
clear |
fn clear(self: *Vector<T>) |
Remove todos os elementos (len → 0). A capacidade é preservada. |
extend |
fn extend(self: *Vector<T>, other: *Vector<T>) |
Adiciona todos os elementos de other; other é deixado intacto. |
free |
fn free(self: *Vector<T>) |
Libera o buffer e a struct. O ponteiro fica inválido após isso. |
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(10, 20, 30, 40);
v.truncate(2); // [10, 20] — capacidade inalterada
println!(v.len()); // 2
let other: *Vector<i32> = Vector::new();
defer other.free();
other.push_all!(7, 8);
v.extend(other); // v agora é [10, 20, 7, 8]; other inalterado
println!(v.len()); // 4
println!(other.len()); // 2
v.clear();
println!(v.is_empty()); // true
return 0;
}
A macro push_all!
macro push_all!($($x:expr),*) {
$( self.push($x); )*
}
Adiciona cada elemento passado. As três formas de chamada são equivalentes:
v.push_all!(1, 2, 3);
Vector::push_all!(v, 4, 5);
Vector::new().push_all!(7, 8, 9);
O builtin vec_of!
vec_of!(a, b, c) constrói e retorna um *Vector<T> em uma única expressão — o tipo do elemento T é inferido a partir do primeiro argumento. É um builtin do compilador, então está disponível em qualquer lugar sem import:
let v: *Vector<i32> = vec_of!(10, 20, 30);
defer v.free();
let names = vec_of!("alice", "bob"); // *Vector<string> inferido
Por ser uma expressão, funciona em qualquer lugar que um valor funciona — um inicializador de let, um argumento de função ou um return:
fn soma(v: *Vector<i32>) -> i32 { /* … */ }
let total = soma(vec_of!(1, 2, 3, 4, 5)); // 15
Todos os elementos devem ser do mesmo tipo; uma chamada mista (vec_of!(1, "dois")) ou vazia (vec_of!(), que não tem como inferir T — use Vector::new()) é rejeitada em tempo de compilação com um erro claro.
Iteração
iter / VecIter<T>
fn iter(self: *Vector<T>) -> *VecIter<T>
pub struct VecIter<T> {
vec: *Vector<T>,
idx: i32,
}
impl<T> VecIter<T> {
pub fn next(self: *VecIter<T>) -> ?T
}
iter() constrói um iterador que produz cada elemento por valor; next() retorna some(x) até o fim, depois none(). O iterador toma empréstimo do buffer do vector durante a travessia — mutar o vector no meio da iteração é comportamento indefinido.
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(10, 20, 30);
let it: *VecIter<i32> = v.iter();
let mut total: i32 = 0;
while true {
match it.next() {
some(x) => { total = total + x; },
none() => break,
}
}
println!(total); // 60
return 0;
}
Combinadores funcionais
Esses métodos são genéricos sobre qualquer Vector<T>. Os que transformam (map/filter/take/skip/take_while/skip_while) retornam um novo *Vector que você possui e deve liberar com free.
| Método | Assinatura | Descrição |
|---|---|---|
map |
fn map<U>(self: *Vector<T>, f: fn(T) -> U) -> *Vector<U> |
Aplica f a cada elemento; retorna um novo vector. |
filter |
fn filter(self: *Vector<T>, p: fn(T) -> bool) -> *Vector<T> |
Mantém apenas os elementos onde p é verdadeiro. |
fold |
fn fold<U>(self: *Vector<T>, init: U, f: fn(U, T) -> U) -> U |
Reduz com acumulador; f(acc, item) retorna o novo acumulador. |
take |
fn take(self: *Vector<T>, n: i32) -> *Vector<T> |
Os primeiros n elementos (limitado ao comprimento). |
skip |
fn skip(self: *Vector<T>, n: i32) -> *Vector<T> |
Todos exceto os primeiros n elementos. |
take_while |
fn take_while(self: *Vector<T>, p: fn(T) -> bool) -> *Vector<T> |
Elementos até p retornar falso (então para). |
skip_while |
fn skip_while(self: *Vector<T>, p: fn(T) -> bool) -> *Vector<T> |
Descarta os elementos iniciais enquanto p é verdadeiro; mantém o restante a partir do primeiro falso. |
any |
fn any(self: *Vector<T>, p: fn(T) -> bool) -> bool |
true se algum elemento satisfaz a condição. Curto-circuita. |
all |
fn all(self: *Vector<T>, p: fn(T) -> bool) -> bool |
true se todos satisfazem. Vector vazio → true (verdade vacuosa). |
find |
fn find(self: *Vector<T>, p: fn(T) -> bool) -> ?T |
Primeiro elemento que satisfaz a condição, ou none(). |
map / filter / fold
fn double(x: i32) -> i32 { return x * 2; }
fn is_even(x: i32) -> bool { return x % 2 == 0; }
fn add(acc: i32, x: i32) -> i32 { return acc + x; }
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(1, 2, 3, 4, 5);
// Vincule cada etapa para que cada resultado com posse seja liberado.
let doubled: *Vector<i32> = v.map(double);
defer doubled.free(); // [2, 4, 6, 8, 10]
let evens: *Vector<i32> = doubled.filter(is_even);
defer evens.free(); // [2, 4, 6, 8, 10]
println!(evens.fold(0, add)); // 30
println!(v.any(is_even)); // true
println!(v.all(is_even)); // false
match v.find(is_even) {
some(x) => println!(x), // 2
none() => println!("none"),
}
return 0;
}
fold é o redutor geral — init semente o acumulador e o tipo de resultado U pode diferir do tipo do elemento. map<U> também muda o tipo do elemento (por exemplo, Vector<i32> → Vector<string>).
take / skip / take_while / skip_while
take/skip fatiam por contagem; take_while/skip_while fatiam por predicado. Todos os quatro retornam um novo vector com posse.
fn lt5(x: i32) -> bool { return x < 5; }
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(1, 3, 7, 2, 9);
let head: *Vector<i32> = v.take(3);
defer head.free(); // [1, 3, 7]
let clamped: *Vector<i32> = v.take(99);
defer clamped.free();
println!(clamped.len()); // 5 (limitado ao comprimento)
let tail: *Vector<i32> = v.skip(2);
defer tail.free(); // [7, 2, 9]
let tw: *Vector<i32> = v.take_while(lt5);
defer tw.free(); // [1, 3] (para no primeiro >= 5)
let sw: *Vector<i32> = v.skip_while(lt5);
defer sw.free(); // [7, 2, 9] (mantém tudo a partir do primeiro >= 5)
println!(tw.len(), sw.len()); // 2 3
return 0;
}
Métodos por tipo de elemento
Glide ainda não tem um trait genérico para números/ordenação, portanto redutores que precisam somar ou comparar elementos residem em blocos concretos de impl Vector<T> por tipo de elemento. Eles só estão disponíveis quando T é exatamente o tipo listado.
Vector<i32>
| Método | Assinatura | Descrição |
|---|---|---|
sum |
pub fn sum(self: *Vector<i32>) -> i32 |
Soma de todos os elementos. Vazio → 0. |
max |
pub fn max(self: *Vector<i32>) -> ?i32 |
Maior elemento, ou none() se vazio. |
min |
pub fn min(self: *Vector<i32>) -> ?i32 |
Menor elemento, ou none() se vazio. |
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(3, 7, 2, 9, 4);
println!(v.sum()); // 25
match v.max() { some(x) => println!(x), none() => {}, } // 9
match v.min() { some(x) => println!(x), none() => {}, } // 2
return 0;
}
Vector<f64>
| Método | Assinatura | Descrição |
|---|---|---|
sum |
pub fn sum(self: *Vector<f64>) -> f64 |
Soma de todos os elementos. Vazio → 0.0. |
max |
pub fn max(self: *Vector<f64>) -> ?f64 |
Maior elemento, ou none() se vazio. |
min |
pub fn min(self: *Vector<f64>) -> ?f64 |
Menor elemento, ou none() se vazio. |
avg |
pub fn avg(self: *Vector<f64>) -> ?f64 |
Média aritmética, ou none() se vazio. |
fn main() -> i32 {
let v: *Vector<f64> = Vector::new();
defer v.free();
v.push_all!(2.0, 4.0, 6.0);
println!(v.sum()); // 12.0
match v.avg() { some(x) => println!(x), none() => {}, } // 4.0
match v.max() { some(x) => println!(x), none() => {}, } // 6.0
match v.min() { some(x) => println!(x), none() => {}, } // 2.0
return 0;
}
Vector<string>
| Método | Assinatura | Descrição |
|---|---|---|
join |
pub fn join(self: *Vector<string>, sep: string) -> string |
Concatena os elementos com sep entre eles. Vazio → "". |
concat |
pub fn concat(self: *Vector<string>) -> string |
Concatena os elementos sem separador. Vazio → "". |
max |
pub fn max(self: *Vector<string>) -> ?string |
Elemento lexicograficamente maior, ou none(). |
min |
pub fn min(self: *Vector<string>) -> ?string |
Elemento lexicograficamente menor, ou none(). |
fn main() -> i32 {
let v: *Vector<string> = Vector::new();
defer v.free();
v.push_all!("apple", "banana", "cherry");
println!(v.join(", ")); // apple, banana, cherry
println!(v.concat()); // applebananacherry
match v.max() { some(s) => println!(s), none() => {}, } // cherry
match v.min() { some(s) => println!(s), none() => {}, } // apple
return 0;
}
Vector<bool>
| Método | Assinatura | Descrição |
|---|---|---|
count_true |
pub fn count_true(self: *Vector<bool>) -> i32 |
Número de elementos true. |
count_false |
pub fn count_false(self: *Vector<bool>) -> i32 |
Número de elementos false. |
all_true |
pub fn all_true(self: *Vector<bool>) -> bool |
true se todo elemento é true. Vazio → true (verdade vacuosa). |
any_true |
pub fn any_true(self: *Vector<bool>) -> bool |
true se pelo menos um elemento é true. Vazio → false. |
fn main() -> i32 {
let v: *Vector<bool> = Vector::new();
defer v.free();
v.push_all!(true, false, true, true);
println!(v.count_true()); // 3
println!(v.count_false()); // 1
println!(v.all_true()); // false
println!(v.any_true()); // true
return 0;
}
Convenções para vector vazio
Redutores que não conseguem produzir um valor sensato em um vector vazio retornam ?T; os aditivos/booleanos usam identidades fixas. Memorize estas para evitar surpresas:
| Chamada | Resultado com vazio |
|---|---|
sum (i32/f64) |
0 / 0.0 |
max / min / avg |
none() |
all (combinador) / all_true |
true (verdade vacuosa) |
any (combinador) / any_true |
false |
count_true / count_false |
0 |
join / concat |
"" |
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
println!(v.sum()); // 0
match v.max() {
some(x) => println!(x),
none() => println!("empty max"), // executado
}
let b: *Vector<bool> = Vector::new();
defer b.free();
println!(b.all_true()); // true (verdade vacuosa)
println!(b.any_true()); // false
return 0;
}