Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Тема
Описание
Доп.

📌 Новый раздел

  • 👾 Best practice
  • Варианты применения

[T; n] - это массив длины n, представленный в виде n соседних экземпляров T

&[T; n] - это просто ссылка на этот массив, представленная в виде тонкого указателя на данные.

[T] - это срез, тип без размера; его можно использовать только через некоторую форму косвенного обращения.

&[T] - называемый срезом, является типом размера. Это жирный указатель, представленный в виде указателя на первый элемент и длину среза.

Используется для операций индексирования buff[index] (в неизменяемых/изменяемых контекстах)

std::ops::Index

Используется для операций индексирования buff[index] в неизменяемых/изменяемых контекстах.


use std::ops::Index;
#[derive(Debug,Default)]
struct Person{
    id:u32
}
struct PersonId(u32);
 
impl Index for Vec{
     type Output = Person;
     fn index(&self,idx: PersonId) -> &Person{
         let idx = idx.0 as usize;
         &self[idx]
        /* for x in self.iter() {
           if x.id as usize == idx  {
              return x;
           }
         }
         &self[0] */
     }
}
fn main(){
   let v:Vec = vec![Person{id:10},Person{id:13}];
   let index:PersonId = PersonId(1);
   print!("{:?}",v[index] );// Person{id:13}
}
use std::marker::PhantomData;
use std::ops::Index;

#[derive(Debug)]
struct IndexVertex<S>(usize, PhantomData<S>);
impl IndexVertex<FromIndex>{
    fn new(index:usize)->Self{
        Self(index,PhantomData)
    }
}

#[derive(Debug)]
struct Vertexes<W>{
    indexes: Vec<Option<Vec<(W, Index Vertex<FromIndex>)>>>
}
impl<W> Vertexes<W>{
    fn new(data: Vec<Option<Vec<(W, IndexVertex<FromIndex>)>>>) -> Self{
        Self{// from -> to
           indexes: data
        }
    }
}
impl<W> Index<IndexVertex<FromIndex>> for Vertexes<W> {
    type Output = Option<Vec<(W, IndexVertex<FromIndex>)>>;
    fn index(&self, index: IndexVertex<FromIndex>) -> &Self::Output {
       &self.indexes[index.0]
    }
}
impl<W> Index<IndexVertex<ToIndex>> for Vertexes<W> {
    type Output = Option<Vec<(W, IndexVertex<ToIndex>)>>;

    fn index(&self, index: IndexVertex<ToIndex>) -> &Self::Output {
    
      &self.indexes[..][index.0] 
        
    }
}
#[derive(Debug,Clone,Copy)]
struct FromIndex;
#[derive(Debug,Clone,Copy)]
struct ToIndex;

/// FromIndex -- ToIndex
impl From<IndexVertex<FromIndex>> for IndexVertex<ToIndex> {
    fn from(index: IndexVertex<FromIndex>) -> IndexVertex<ToIndex> {
        IndexVertex(index.0,PhantomData)
    }
}
/// ToIndex -- FromIndex
impl From<IndexVertex<ToIndex>> for IndexVertex<FromIndex> {
    fn from(index: IndexVertex<ToIndex>) -> IndexVertex<FromIndex> {
        IndexVertex(index.0,PhantomData)
    }
}

fn main(){
   let index = IndexVertex::new(1);
  
    let data = vec![ 
       Some(vec![(8,IndexVertex::new(1)),(4,IndexVertex::new(2))]), // 0=>1,2
       Some(vec![(9,IndexVertex::new(2))]),       // 1=>2
       Some(vec![(6,IndexVertex::new(0))]),       // 2=>0
    ];
        
    let vertexes = Vertexes::new(data);
    let from_index = IndexVertex::new(0);
    for vertexes in vertexes[from_index].iter(){
        for v  in vertexes{
             println!("W={} index={}",v.0,v.1.0);
        }
    }
    
    let from_index = IndexVertex::new(0);
    let to_index:IndexVertex<ToIndex> = from_index.into();
     for vertexes in vertexes[to_index].iter(){ ... }
}

std::ops::IndexMut

nucleotide_count[Nucleotide::A] == *nucleotide_count.index(Nucleotide::A)


use std::ops::Index;
enum Nucleotide {
    A, C, G, T,
}
struct NucleotideCount {
    a: usize, c: usize, g: usize,  t: usize,
}
impl Index for NucleotideCount {
    type Output = usize;

    fn index(&self, nucleotide: Nucleotide) -> &Self::Output {
        match nucleotide {
            Nucleotide::A => &self.a,
            Nucleotide::C => &self.c,
            Nucleotide::G => &self.g,
            Nucleotide::T => &self.t,
        }
    }
}
fn main(){
    let nucleotide_count = NucleotideCount {a: 14, c: 9, g: 10, t: 12};
    assert_eq!(nucleotide_count[Nucleotide::A], 14);
    assert_eq!(nucleotide_count[Nucleotide::C], 9);
    assert_eq!(nucleotide_count[Nucleotide::G], 10);
    assert_eq!(nucleotide_count[Nucleotide::T], 12);
}

use std::ops::{Index, IndexMut};
#[derive(Debug)]
enum Side {
    Left,
    Right,
}
#[derive(Debug, PartialEq)]
enum Weight {
    Kilogram(f32),
    Pound(f32),
}
struct Balance {
    pub left: Weight,
    pub right: Weight,
}
impl Index for Balance {
    type Output = Weight;

    fn index(&self, index: Side) -> &Self::Output {
        println!("Accessing {index:?}-side of balance immutably");
        match index {
            Side::Left => &self.left,
            Side::Right => &self.right,
        }
    }
}
impl IndexMut for Balance {
    fn index_mut(&mut self, index: Side) -> &mut Self::Output {
        println!("Accessing {index:?}-side of balance mutably");
        match index {
            Side::Left => &mut self.left,
            Side::Right => &mut self.right,
        }
    }
}
fn main(){
    let mut balance = Balance {
        right: Weight::Kilogram(2.5),
        left: Weight::Pound(1.5),
    };
// В этом случае `balance[Side::Right]` — это сахар для 
// `*balance.index(Side::Right)`, поскольку мы только читаем `balance[Side::Right]`, а не записываем его.
    assert_eq!(balance[Side::Right], Weight::Kilogram(2.5));

// Однако в данном случае `balance[Side::Left]` — это сахар для 
// `*balance.index_mut(Side::Left)`, поскольку мы пишем `balance[Side::Left]`.
    balance[Side::Left] = Weight::Kilogram(3.0);
}

«Вектор» — это динамический или, по-другому, «растущий» массив, реализованный в виде стандартного библиотечного типа Vec<T>

Умный указатель так как владеют некоторой памятью и позволяют вам манипулировать ею

VecDeque

VecDeque(произносится как «век-дек») — это Vec, оптимизированный для (т. е. хорошо справляющийся) pop (выталкивания) предметов как спереди, так и сзади. Rust имеет VecDeque, потому что Vec отлично подходят для выталкивания сзади (последнего предмета), но не так хороши спереди. Когда вы используете .pop() на Vec, он просто снимает последний предмет справа, и больше ничего не перемещается. Но если вы удалите предмет из любого места внутри Vec, все предметы справа от него перемещаются на одну позицию влево.

Вы можете увидеть это в описании для .remove():

"Удаляет и возвращает элемент в позиции index внутри вектора, сдвиг всех элементов после него влево."

Минус VecDeque:

Доступ по индексу аналогичен Vec (O(1)), но он менее оптимален для операций, связанных только с концом структуры данных, потому что в памяти используется кольцевой буфер, и операции могут быть чуть сложнее. VecDeque: Кольцевой буфер может быть избыточным, особенно если редко вставлять или удалять элементы с начала. Удаление из середины работает, но оно требует сдвига элементов, что делает операцию линейной по времени (O(n)), аналогично тому, как это происходит в Vec

crate slab

slab, generational_arena или slotmap - инструменты хранения в куче, которые безопасно обходят заимствования (и работают быстро).

crate index_vec, arrayvec, indexmap - вариации на тему Vec и HashMap.

Если выделяется много значений одного типа, может быть более эффективным предварительное выделение необходимого хранилища. Поскольку размер типа единообразен, можно избежать фрагментации памяти. Операции хранения, очистки и поиска становятся очень дешевыми.

AsRef<[T]> 
AsMut<[T]>
Deref 
DerefMut
Borrow<[T]>
BorrowMut<[T]>
Extend
std::io::Write
From

fn main(){
    let mut vec = Vec::with_capacity(10);  
    // AsRef<[T]> 
    let slice:&[i32] = vec.as_ref();
    // AsMut<[T]>
    let m_slice:&mut [i32] = vec.as_mut(); 

    // Deref 
    let slice:&[i32] = &vec;
    // DerefMut
    let m_slice:&mut [i32] = &mut vec; 

    use std::borrow::Borrow;
    use std::borrow::BorrowMut;
    // Borrow<[T]>
    let slice:&[i32] = vec.borrow();
    // BorrowMut<[T]>
    let m_slice:&mut [i32] = vec.borrow_mut();

    // Extend<&'a T> ,  Extend
    vec.extend([1,2,3]);
    vec.extend(vec![1,2,3]);

    use std::io::Write;
    let mut buf = vec![1u8,2,3];
    let _ = buf.write(&[1u8,2,3]);

    // From<&str> for Vec
    let vec:Vec = Vec::from("123");
    let vec:Vec = "123".into();
    // From<&[T]> for Vec
    let vec:Vec = Vec::from([1,2,3]);
}

Мутация встроенной коллекции

Непересекающийся захват в замыканиях

rustcamp/2_2_mem_replace

capture-in-closures

struct Names {
    exclusions: Vec<String>,
    names: HashSet<String>,
}

impl Names {
    fn apply_exclusions(&mut self) {
        self.exclusions.drain(..).for_each(|name| {
            self.names.remove(&name);
        })
    }
}
fn main(){}

impl Names {
    fn apply_exclusions(&mut self) {
        let mut exclusions = mem::take(&mut self.exclusions);
        exclusions.drain(..).for_each(|name| {
            self.remove_name(&name);
        });
    }

    fn remove_name(&mut self, name: &str) {
        self.names.remove(name);
    }
}
fn main(){}

Как устроен Vec

#[may_dangle]

lukefleed

Консервативная проверка Drop

Компилятор видя в сигнатуре реализации трейта Drop - drop(&mut self) предполагает худший случай, то что мы можем использовать self, а если self это ссылка то она должна иметь время жизни строго больше самого контейнера.

Drop-check:

  • Для generic типов impl<T> Drop for Foo<T> { ... } компилятор требует:
    T должен быть валиден на момент срабатывания drop(Foo<T>)
  • А если T = &'a U, то это превращается в:
    'a должен переживать Foo

И такое поведение, является проблемой почти для всех контейнеров стандартной библиотеки:

Vec<T>
Box<T>
Option<T>
BinaryHeap<T>

Например мы бы не смогли использовать контейнер так:

fn f<'a>(x: &'a i32) {
    let v: Vec<&'a i32> = vec![x];
} // ❌ 'a обязан переживать v

Что делает Vec<&T> практически бесполезным, навязывая лишние lifetime-ограничения, которых в реальности нет.

Как это исправляют #[may_dangle] — это unsafe-обещание автора типа - Я гарантирую, что drop() не будет обращаться к T

В стандартной библиотеке Rust (std) Vec<T> делает:

unsafe impl<#[may_dangle] T> Drop for Vec<T> { … }

Это nightly-only feature внутри std, но сам стандартный library crate скомпилирован и доступен в stable.

И тогда компилятор:

  • снимает требование «T должен быть жив»
  • разрешает dangling T при drop (разрешает иметь ссылку или указатель указывающую на память, которая уже недействительна в связи с уничтожением или время жизни за пределами сроков заимствования)
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(unused_assignments)]

// nightly для #[may_dangle]
#![feature(dropck_eyepatch)] // для #[may_dangle]


use std::fmt::Debug;

#[derive(Debug)]
struct MyVec<T: Debug>{
    value: T
} 
impl<T: std::fmt::Debug> Drop for MyVec<T> {
    fn drop(&mut self) {
       println!("{:?}",self.value);
    }
}

// Вариант с #[may_dangle]
#[derive(Debug)]
struct MyVec2<T: Debug>{
    value: T
} 
// Это безопасно только если ты ручаешься, что drop() не разыменовывает T
unsafe impl<#[may_dangle]T: std::fmt::Debug> Drop for MyVec2<T> {
    fn drop(&mut self) {
       // Если твоя программа реально создаст dangling ссылку и разыменует её в drop, это UB.
       // println!("MyVec2:{:?}",self.value);
    }
}
 
fn make_myvec<'a>(x: &'a i32) -> MyVec<&'a i32> {
    MyVec { value: x }
}

fn make_myvec2<'a>(x: &'a i32) -> MyVec2<&'a i32> {
    MyVec2 { value: x }
}

fn make_vec<'a>(x: &'a i32) -> Vec<&'a i32> {
    vec![x]
}

fn main() {
    let v:MyVec<&i32>;
    let v2:MyVec2<&i32>;
    let u:Vec<&i32>;
    {
        let data = 42;
 
        v2 = make_myvec2(&data);// ✅ компилируется
        u = make_vec(&data); // ✅ компилируется
        
        // Rust консервативно считает, что в drop() ты можешь использовать self.value
        //v = make_myvec(&data); // ❌ компилятор выдаст ошибку
    }
}

Зачем Vec нужен PhantomData

struct Vec<T> {
    ptr: *mut T,
    len: usize,
    cap: usize,
    _marker: PhantomData<T>,
}

Vec хранит не сами данные, а указатель ptr: *mut T — raw pointer.

Компилятор не видит владения через raw pointer, потому что он не трекает память в heap за пределами типовой системы.

Но Rust должен знать, кто владеет T, чтобы:

  • правильно проверять lifetimes
  • проверять Send/Sync
  • автоматически реализовывать auto traits

Для подсказки компилятору что Vec владеет данными используется логическая подсказка через PhantomData<T>

Свои методы для std типов


trait MyTrait{
   fn gogo(&mut self);
}
impl  MyTrait for [T]{
    fn gogo(&mut self){
        println!("{}",self.len());
    }
}
impl  MyTrait for Vec where [T]:MyTrait{
    fn gogo(&mut self){
        println!("{}",self.len());
    }
}
impl MyTrait for i32{
    fn gogo(&mut self){
        println!("{}",self);
    }
}
fn main(){
    let mut v = vec![1,2,3];
    v.gogo();

    [1;5].gogo();
    4_i32.gogo();
}

Инициализированный вектор нужного размера


fn main(){
    // Если не указать тип вектора при создании и не проинициализировать его будет ошибка при его выводе 
    let mut vec:Vec;
    print!("{:?}",vec);

    // Инициализированный вектор нужного размера
    let count = w*h;
    let mut buf:Vec = vec![0u8; count];

    struct Queue{
        queue:Vec>,
    }
    self.queue = vec![Some(T::default()); size]
}

Способы передать mut Vec в thread

  • *mut T

  • split_at_mut(indx)

  • UnsafeCell


fn main(){
    let mut arr:Vec = vec![1,2,3,4,5];
    let ptr:*mut Vec = &mut arr;
     
    let addr:usize = ptr as usize;
   
    let mut buff = vec![]; 
    let h1 = std::thread::spawn(move ||{
       let mut ptr2:*mut Vec = addr as *mut Vec;
       let mut arr2:&mut Vec = unsafe {&mut *ptr2};
       arr2[4]=9;
    });
    buff.push(h1);
    let h2 = std::thread::spawn(move ||{
       let mut ptr2:*mut Vec = addr as *mut Vec;
       let mut arr2:&mut Vec = unsafe {&mut *ptr2};
       arr2[3]=8;
    });
    buff.push(h2);
    for h in buff{
        h.join().unwrap();
    }
    assert_eq!(vec![1, 2, 3, 8, 9],arr);
}


fn main(){
    let mut arr:Vec = vec![1,1,1,1,1];
    let (left, right) = arr.split_at_mut(2);
    
    std::thread::scope(|s| {
        s.spawn(|| {
            left[0]=9;
        });
        s.spawn(|| {
           right[0]=8;
        });
    });
 
    assert_eq!(vec![9, 1, 8, 1, 1],arr);
    println!("{:?}",arr);// [9, 1, 8, 1, 1]
}

Еще split_as_mut


use crossbeam; // 0.8.2
fn main() {
    let mut vec: Vec = (0..10).collect();
    crossbeam::scope(|scope|{
        let (l,r):(&mut [u32],&mut [u32]) = vec.split_at_mut(5);
        scope.spawn(move |_| {
            l.reverse()
        });
        scope.spawn(move |_| {
            r.reverse()
        });
    });
    assert_eq!(vec![4, 3, 2, 1, 0, 9, 8, 7, 6, 5], vec);
}
}


use std::sync::Arc;
use std::cell::UnsafeCell;
use std::marker::Sync;

#[derive(Debug)]
struct NotThreadSafe {
    value: UnsafeCell>,
}

unsafe impl Sync for NotThreadSafe {}

impl NotThreadSafe {
    fn new(v:Vec)->Self{
       NotThreadSafe{value:UnsafeCell::new(v)}
    }
}
fn main() {
     let v = Arc::new(NotThreadSafe::new(vec![1;5]));
     let mut buff = vec![]; 
     let v_clone_1 = Arc::clone(&v);
     let v_clone_2 = Arc::clone(&v);
     let h1 = std::thread::spawn( move ||{
        let data:*mut Vec = v_clone_1.value.get();
        if !data.is_null(){
            unsafe{
               let data_vec:&mut Vec = &mut *data;
               data_vec[4]=9;
            }
        } 
        
    });
    buff.push(h1);
        let h2 = std::thread::spawn( move ||{
        let data:*mut Vec = v_clone_2.value.get();
        if !data.is_null(){
            unsafe{
               let data_vec:&mut Vec = &mut *data;
               data_vec[3]=8;
            }
        } 
    });
    buff.push(h2);
    for h in buff{
        h.join().unwrap();
    }
    
    let mut data = v.value.get();
    if !data.is_null(){
        unsafe{
           let data_vec:&Vec = &*data;
           println!("{:?}",data_vec);
           assert_eq!(vec![1, 1, 1, 8, 9],data_vec.clone());
        }
    } 
}

Размер вектора это размер трех частей которые лежат на стеке:

  • 1 указатель на данные
  • 2 длина вектора
  • 3 его ёмкость

src = { data: *mut [i32], length: usize, capacity: usize }

Box для n элементов:

pub struct Vec<T> {
    /// Указатель на данные в куче.
    ptr: *const T,
    /// Длина.Количество элементов в векторе.
    /// Инвариант: len <= capacity.
    len: usize,
    /// Емкость.Количество слотов в векторе (capacity).
    /// Увеличивается в 2 раза при заполнении длины.
    cap: usize,
}

Вектор определяется тремя словами: указатель на данные, длина вектора и его ёмкость. Ёмкость определяет, сколько памяти резервируется для вектора. Вектор может увеличиваться, пока его длина меньше его ёмкости. При необходимости превысить заданное значение объёма, вектору повторно выделяется память большего объёма.

fn main(){
    use std::mem::size_of;
    assert_eq!(size_of::<Vec<i32>>(), size_of::<usize>() * 3);

    let mut xs = vec![1, 2, 3];
    xs.push(4);
    assert_eq!(xs.len(), 4);
    assert_eq!(xs[2], 3);
}

fn main(){
    #![feature(vec_into_raw_parts)]

    let v: Vec<i32> = vec![-1, 0, 1];

// После вызова этой функции вызывающая сторона отвечает за память, ранее управляемую Vec. 
// Единственный способ сделать это - преобразовать исходный указатель, длину и емкость обратно в Vec 
// с from_raw_parts функцией, позволяя деструктору выполнить очистку.
    let (ptr, len, cap) = v.into_raw_parts();

    let v_rebuilt: Vec<i32> = unsafe {
// Теперь мы можем вносить изменения в компоненты, 
// например преобразовывать необработанный указатель в совместимый тип.`let ptr = ptr as *mut u32;` с потерей отрицательных значений

// отдадим необработанный указатель обратно для освобождения занимаемой им памяти после выхода из области видимости (RAII)  
    Vec::from_raw_parts(ptr, len, cap)
    };
    assert_eq!(v_rebuilt, [-1, 0, 1]); 
}

fn main(){
    let v: Vec<i32> = vec![-1, 0, 1];
    let mut m = std::mem::ManuallyDrop::new(v); 
    let (ptr, len, cap) = (m.as_mut_ptr(),m.len(),m.capacity());

// Для корректно освобождения ресурсов:
// - или обратно преобразовать в Vec и тогда стандартный Drop отработает
    let v_rebuilt: Vec<i32> = unsafe { 
        Vec::from_raw_parts(ptr, len, cap)
    };
    assert_eq!(v_rebuilt, [-1, 0, 1]); 
// - либо вызвать освобождение ManuallyDrop::drop
    unsafe{
        ManuallyDrop::drop(&mut m);// ps. но не оба сразу способа `free(): double free detected in tcache 2`
    }
}

fn main(){
    let mut my_vec: Vec<i32> = vec![-1, 2, 3];
    let my_vec_ptr:*mut i32 = my_vec.as_mut_ptr();// получить необработанный указатель указателя на данные
   
    //let (my_vec_ptr, len, cap) = my_vec.into_raw_parts();// получить необработанный указатель указателя на данные, емкость и длину 
    let new_vec: Vec<i32> = unsafe{
        // можем мутировать данные
        for i in 0..len as i32 {
            std::ptr::write(my_vec_ptr.offset(i as isize), 4 + i);
        }
        // или так
        *my_vec_ptr.add(2) = 222_i32;
        // отдадим необработанный указатель обратно для освобождения занимаемой им памяти после выхода из области видимости (RAII)  
        Vec::from_raw_parts(my_vec_ptr, len,cap)
    };
    println!("new_vec = {:?}", new_vec);// [4, 5, 222]
    let my_vec_addr = my_vec_ptr as usize;// преобразовать необработанный указатель в целое число
    println!("address = {:X}", my_vec_addr);// 556BE0B489D0

}

Пример утечки данных

При получении сырого указателя вектора into_raw_parts мы обязуемся освободить память используя Vec::from_raw_parts, иначе память никто не освободит и она будет занятой, но не используемой как раз для vec_2 мы не освобождаем память и в отчете dhat видно сколько произошло утечки памяти

ManuallyDrop - это оболочка типа, которая запрещает компилятору Rust автоматически вызывать деструктор базового типа.

dh-manual

File Cargo.toml:

[dependencies]
dhat = "0.3" 

[[example]]
name = "dhat"
path ="examples/dhat_ex.rs"

[profile.release]
debug = 1

[features]
dhat-heap = []    # if you are doing heap profiling
dhat-ad-hoc = []  # if you are doing ad hoc profiling


#![feature(vec_into_raw_parts)]
#[cfg(feature = "dhat-heap")]
#[global_allocator]
static ALLOC: dhat::Alloc = dhat::Alloc;
 
// Run:
//  cargo +nightly run --example dhat --features dhat-heap 
//
// Show:
//  open url https://nnethercote.github.io/dh_view/dh_view.html and send file `dhat-heap.json`
//
// Output:
// dhat: Total:     6,000 bytes in 2 blocks
// dhat: At t-gmax: 6,000 bytes in 2 blocks
// dhat: At t-end:  4,000 bytes in 1 blocks (Должно быть 0 bytes)
//
// Где:
// dhat: Total:     6,000 bytes in 2 blocks => [0i16;1000] + [0i32;1000] = 2000 + 4000 = 6000 bytes
// dhat: At t-end:  4,000 bytes in 1 blocks => из 6000 байт аллоцированных осталось не освобожденных 4000 байт т.е. освободили только 2000 байт ([0i16;1000])
fn main(){
    // dhat block #############################################################################
    #[cfg(feature = "dhat-heap")]
    let _profiler = dhat::Profiler::new_heap();
    // ########################################################################################
    {
        let v: Vec = vec![0i16;1000];// 2000 bytes (1000*2 bytes)
        let v_2: Vec = vec![0i32;1000]; // 4000 bytes (1000*4 bytes)

        // После вызова этой функции вызывающая сторона отвечает за память, ранее управляемую Vec. 
        // Единственный способ сделать это - преобразовать исходный указатель, длину и емкость обратно в Vec 
        // с from_raw_parts функцией, позволяя деструктору выполнить очистку.
        let (ptr, len, cap) = v.into_raw_parts();

        let (ptr_2, len_2, cap_2) = v_2.into_raw_parts();

        let v_rebuilt: Vec = unsafe {
            // Теперь мы можем вносить изменения в компоненты, 
            // например преобразовывать необработанный указатель в совместимый тип.`let ptr = ptr as *mut u32;` с потерей отрицательных значений

            // отдадим необработанный указатель обратно для освобождения занимаемой им памяти после выхода из области видимости (RAII)  
            Vec::from_raw_parts(ptr, len, cap)
        };
    }
}

Преобразовать тип вектора i16 => u8


fn main(){
    let mut samples_src:Vec = vec![4;8];         
// ManuallyDrop - это оболочка типа, которая запрещает компилятору Rust автоматически вызывать деструктор базового типа.
    let mut m = std::mem::ManuallyDrop::new(samples_src); // или into_raw_parts но самостоятельно освободить указатель через from_raw_parts

    let (p,len,cap) = (m.as_mut_ptr(),m.len(),m.capacity());
            
// корректно освободить ресурсы
    let samples_dst: Vec = unsafe { Vec::from_raw_parts(p as *mut u8, len, cap) };
// либо
    unsafe{
       ManuallyDrop::drop(&mut m);// ps. но не оба сразу способа `free(): double free detected in tcache 2`
    }
}

boxed-slices умньшение размера вектора (для множества векторов)

boxed-slices

Альтернативой коробочным ломтикам является ThinVec, из crate thin_vec. Функционально он эквивалентен Vec, но хранит длину и емкость в том же распределении, что и элементы (если они есть). Это означает, что size_of::<ThinVec<T>> это всего лишь одно слово.

Упакованные ломтики

Векторы Rust содержат три слова: длина, емкость и указатель. Если у вас есть вектор, который вряд ли будет изменен в будущем, вы можете преобразовать его в boxed-slices с помощью Vec::into_boxed_slice. Помещенный в boxed slices содержит только два слова - длину и указатель. Любая избыточная емкость элемента сбрасывается, что может вызвать перераспределение.


fn main(){
    let v: Vec = vec![1, 2, 3];
    assert_eq!(size_of_val(&v), 3 * size_of::());

    let bs: Box<[u32]> = v.into_boxed_slice();
    assert_eq!(size_of_val(&bs), 2 * size_of::());
}

Упакованный фрагмент можно преобразовать обратно в вектор slice::into_vec без клонирования или перераспределения.

перебор &mut Vec<T>/&mut [T] вложенным циклом

т.е. мы не берем ссылки на вектор кроме той что уже есть в scope


// Временная сложность алгоритма - квадратичная сложность O(N^2)
fn algo_7_bubble_sort(v:&mut [i32]){
    for i in 0..v.len()-1 {
        for j in 0..v.len()-1 {
            if v[j] > v[j+1]{
                let swap = v[j];
                v[j]=v[j+1];
                v[j+1]=swap;
            }
        }
    }
}
pub fn main() {
    let mut v = vec![1,3,2,1];
    algo_7_bubble_sort(&mut v);
    assert_eq!(v.as_slice(),&[1,1,2,3]);
}

Формирование файла с данными


fn main(){
    let mut inp_file = File::create(Path::new("RGraph/data2.js")).unwrap();

    let mut f = File::open("source/12345.WAV").unwrap();
    inp_file.write( b"var dataarr = [").unwrap();
    let take=50;
    for (index,byte) in f.bytes().skip(44).take(take).enumerate() {
        inp_file.write(format!("{}",byte.unwrap()).as_bytes()).unwrap();
        if index

это временный хак, позволяющий надежно и эффективно расширить Vec

vecpush_all

Клон полностью вышел из-под нашего контроля и может свободно паниковать. Если это так, наша функция завершится раньше, поскольку длина Vec будет слишком большой. Если Vec просмотреть или удалить, неинициализированная память будет прочитана! Исправить в этом случае довольно просто. Если мы хотим гарантировать, что значения, которые мы клонировали, будут удалены, мы можем установить len каждую итерацию цикла. Если мы просто хотим гарантировать, что неинициализированную память невозможно будет наблюдать, мы можем установить len цикл after.


// это временный хак, позволяющий надежно и эффективно расширить Vec
fn main() {
    let mut v = Vec::new();
    push_all(&mut v,&[4,5,6]);
    println!("{:?}",v);
}
fn push_all(mut vec: &mut Vec, to_push: &[T]) {
    vec.reserve(to_push.len());
    unsafe {
        // не может переполниться, потому что мы только что зарезервировали это
        vec.set_len(vec.len() + to_push.len());

        for (i, x) in to_push.iter().enumerate() {
            vec.as_mut_ptr().add(i).write(x.clone());
        }
    }
}

Вектор типа enum

вектор одного типа но разных значений


#[derive(Debug,Clone)]
enum T{
    INT(i32),
    STRING(String),
    FLOAT(f32)
}
use std::convert::From;
impl From for i32 {
    fn from(item: T) -> i32 {
       match item {
           T::INT(e) => e,
           _ => panic!("Type error")
       }
    }
}
impl From for String {
    fn from(item: T) -> String {
       match item {
           T::STRING(e) => e,
           _ => panic!("Type error")
       }
    }
}
fn main() {
 let v:Vec = vec![T::INT(2),T::STRING("Hello".to_owned())];
 let i:i32 = v[0].clone().into();
 let s:String = v[1].clone().into();
 
 println!("{} {}",i ,s);
}
  • new - создание пустого Vec<T>
  • with_capacity - создание пустого Vec<T> с указанной емкостью

  • len - возвращает количество элементов в векторе
  • is_empty - проверка на пустоту

  • remove - удаляет и возвращает элемент в позиции index в векторе, сдвигая все влево.
  • pop - удалить с конца
  • swap_remove - Удаляет элемент из вектора по индексу и возвращает его, и на его место перемещается последний ел.
  • retain - фильтр,сохраняет только элементы, указанные в предикате.
  • leak - Потребляет и сливает Vec, возвращающие изменяемую ссылку на содержание
  • retain_mut - фильтр,сохраняет только элементы, указанные в предикате.
  • into_flattened - конвертирует многомерный массив в одномерный
  • into_boxed_slice - преобразует вектор в Box<[T]>

  • push - вставить в конец
  • push_within_capacity - Добавляет элемент, если имеется достаточная свободная емкость
  • insert - Вставляет элемент в позицию index в векторе, сдвигая все элементы вправо.
  • append - Перемещает все элементы other вектора в Self, оставляя other пустым
  • extend_from_slice - Расширение из среза
  • extend_from_within - Копирует элементы из диапазона src в конец вектора

  • splice - Заменяет значениями из нового вектора и возвращает замененные элементы
  • drain - Итератор удаляет диапазон в векторе и возвращает удаленные элементы.
  • dedup - Удаляет последовательные повторяющиеся элементы
  • dedup_by_key - фильтр, удаляет элементы не соответствующие условию
  • dedup_by - фильтр, удаляет одинаковые элементы рядом (при отсортированных данных)

  • clear - Очищает вектор, удаляя все значения.(на емкость не влияет)
  • truncate - Укорачивает вектор, сохраняя первые len элементы и отбрасывая остальные.
  • resize_with - Изменяет размер
  • resize - Изменяет размер
  • capacity - количество элементов в векторе без необход. распределения
  • shrink_to_fit - Максимально сжимает емкость вектора
  • reserve - Создает емкость для вставки доп. данных (self.len() + доп. данные )
  • reserve_exact - Резервирует минимальную емкость для доп. данных
  • set_len - Заставляет длину вектора быть равной new_len.(лучше truncate,resize,extend,clear)
  • shrink_to - Уменьшает емкость вектора с нижней границей.
  • try_reserve - Пытается зарезервировать емкость для доп. данных
  • try_reserve_exact - Пытается зарезервировать минимальную емкость для доп. данных
  • spare_capacity_mut - Возвращает оставшуюся свободную емкость вектора как часть MaybeUninit<T>

  • as_slice - Извлекает фрагмент, содержащий весь вектор
  • as_mut_slice - Извлекает изменяемый фрагмент всего вектора.
  • split_off - Разбивает коллекцию на две части по заданному индексу

  • as_ptr - Возвращает необработанный указатель на буфер вектора
  • as_mut_ptr - Возвращает небезопасный изменяемый указатель на буфер вектора.
  • from_raw_parts_in - Создает Vec<T, A> непосредственно из ptr, len, capacity
  • from_raw_parts - Создает Vec<T> непосредственно из необработанных данных другого вектора

  • split_at_spare_mut - Возвращает содержимое вектора в виде части T, а также оставшуюся свободную емкость вектора в виде части MaybeUninit<T>

Nightly:

  • new_in - Создает новый, пустой Vec<T, A>
  • with_capacity_in - Создает новый пустой Vec<T, A> с указанной емкостью
  • from_raw_parts_in - Создает Vec<T, A> непосредственно из необработанных данных вектора
  • into_raw_parts - Разлагает Vec<T> на необработанные компоненты
  • into_raw_parts_with_alloc - Разлагает Vec<T> на необработанные компоненты
  • allocator - Возвращает ссылку на базовый распределитель.
  • drain_filter - итератор использует замыкание, чтобы определить, следует ли удалить элемент.

fn main(){
    let v1: Vec = Vec::new();// через new (Vec::::new())
    let mut v1: Vec = Vec::with_capacity(99);
    let v:Vec = Vec::default();
    let v2: Vec = vec![];// через macro vec! (Пустой вектор создается нулевой емкостью и выделяет память 4, 8, 16 и 32)
    let v = vec![1i32;3]; // [1,1,1]
    let mut v3 = vec![1u8, 2, 3, 4, 5];// v: Vec
    let v:Vec = (0..N).map(|i|format!("{}",i)).collect::>();

    println!("Третий элемент вектора v равен {}", v3[2]);

    for i in &v3 {
        println!("Ссылка {}", *i);// разименовывание , println может сам это делать
    }

    for i in &mut v3 {
        println!("Изменяемая ссылка {}", *i);
    }

    //Владение вектором
    // передача владения циклу for, после него вектор удаляется из стека и кучи
    for i in v3 {
        println!("Владение вектором и его элементами {}", i);
    }

    //По вектору можно легко итерироваться
    for x in xs.iter() {
        println!("> {}", x);
    }
    //Благодаря методу `iter_mut`, можно обойти вектор при этом изменить каждое значение в нем.
    for x in xs.iter_mut() {
        *x *= 3;
    }
    println!("Обновленный вектор: {:?}", xs);

    while let Some(top) = v3.pop() {
        //13,12,11,3,
        print!("{},", top);
    }
}

into_iter потребляем коллекцию


fn main(){
    let xs = [1,2,3];
    let xs = vec![1,2,3];
    let mut it = xs.into_iter();
    while let Some(x) = it.next() {
       println!("{:?}",x);    
    }
}

clone_from

может избежать ненужного выделения памяти для емкости, используется для клонирования вектора в существующий с нужной емкостью, а не той что у клонируемого


fn main(){
    let mut v1: Vec = Vec::with_capacity(99);
    let v2: Vec = vec![1, 2, 3];
    v1.clone_from(&v2); 
    assert_eq!(v1.capacity(), 99);
}
  • Vec::new() или vec![] - создание пустого вектора
  • v.push(6) - вставить в конец
  • v.contains(&6) - проверка существования
  • v.pop() - удалить с конца
  • v.first() v.first_mut() - первый элемент
  • v.last() v.last_mut() - последний элемент
  • v.extend([11, 12, 13].iter().cloned()) - расширение
  • v.len()
  • v.is_empty()

fn main(){
    let v:Vec = vec![1;5]; // [1,1,1,1,1]
 
   let mut v1: Vec = Vec::new();
    v1[1]=v1[1]+4;
    if !v1.contains(&6){ // проверка существования
      v1.push(6); // вставка в конец
    }
    let item = v1.pop();
    println!("{:?}",item);// Some(10)

    v1.extend([11, 12, 13].iter().cloned());// расширение

    println!("{}",v1.len());// 4
    assert!(!v.is_empty());
    while let Some(top) = v1.pop() {
        print!("{},", top);  //13,12,11,3,
    }
}


fn main(){
    let mut v = vec![1,2,3];
    let first:&i32 = v.first().unwrap();
    assert_eq!(&1, first);
    assert_eq!(&3, v.last().unwrap());
    if let Some(first) = v.first_mut() {
        *first = 5;
    }
    if let Some(last) = v.last_mut() {
        *last = 10;
    }
    assert_eq!(vec![5,2,10], v);
}

Vec::with_capacity предполагаемая емкость вектора

Используйте, with_capacity когда вы точно знаете, сколько элементов будет вставлено или, по крайней мере, имеет разумную верхнюю границу для этого числа.

capacity(&self) -> usize Возвращает количество элементов, которые вектор может удерживать без перераспределения.

shrink_to_fit() - Максимально уменьшает емкость вектора

Для оптимальной производительности коллекции обычно избегают сокращения самих себя. Если вы считаете, что коллекция не будет содержать больше элементов или просто нужна память, shrink_to_fit метод предложит коллекции сжать массив подстановки до минимального размера, способного удерживать его элементы.

reserve(&mut self, additional: usize) После вызова резерва емкость будет больше или равна self.len () + дополнительно // reserve_exact(&mut self, additional: usize)

Когда вы ожидаете большого притока элементов, reserve семейство методов можно использовать, чтобы намекать на сбор, сколько места он должен сделать для предстоящих предметов


fn main(){
    let mut vec = Vec::with_capacity(10); увеличивает скорость работы избегая не нужного выделения памяти в процессе работы !!!

    vec.extend_from_slice(&[1,2,3,4,5,6,7,8,9,10,11]); // перераспределение емкости вектора
    assert_eq!(vec.capacity(), 20);
}


fn main(){
     let mut vec = Vec::with_capacity(10);
     vec.extend([1, 2, 3].iter().cloned());
     assert_eq!(vec.capacity(), 10);
     vec.shrink_to_fit();
     assert!(vec.capacity() >= 3);
}


fn main(){
 // После создания , резервирует емкость
//reserve(&mut self, additional: usize)
     let mut vec = vec![1];
     vec.reserve(10);
     assert!(vec.capacity() >= 11);
    //Резервирует минимальную емкость для получения еще большего количества элементов, которые нужно вставить в данный Vec 
    //Предпочитайте reserve, если ожидаются будущие вставки.
// reserve_exact(&mut self, additional: usize)
     let mut vec = vec![1];
     vec.reserve_exact(10);
     assert!(vec.capacity() >= 11);
}

set_len() Устанавливает длину вектора.

Необходимо убедиться, что вектор на самом деле является указанным размером


fn main(){
    use std::ptr;
    let mut vec = vec!['r', 'u', 's', 't'];
    unsafe {
        ptr::drop_in_place(&mut vec[3]);
        vec.set_len(3);
    }
    assert_eq!(vec, ['r', 'u', 's']);
}

В этом примере происходит утечка памяти, так как ячейки памяти, принадлежащие внутренним векторам, не были освобождены до вызова set_len


fn main(){
    let mut vec = vec![vec![1, 0, 0], vec![0, 1, 0], vec![0, 0, 1]];
    unsafe {
        vec.set_len(0);
    }
// или
    let mut vec: Vec = Vec::new();
    unsafe {
        vec.set_len(4);
    }
}

Переместить элемент из вектора

pop() - удалить с конца

std::mem::replace()

swap_remove(1) - Удаляет элемент из вектора по позиции и возвращает его. Ставя на его место последний элемент

Плюс swap_remove в том что он быстрый O(1) и не сдвигает все элементы как при remove Минус, последний элемент встает на место удаляемого

*retain(|&x| x%2 == 0) - Сохраняет только элементы, заданные предикатом

**retain_mut **


fn main(){
    // 1. Взять последнее значение
    let fifth = v.pop().unwrap();

    // 2. Взять значение из середины вектора и переместить на его место
    let mut value:Vec = vec![1,2,3,4,5];
    value.swap_remove(0); // [1,2,3,4,5] => [5, 2, 3, 4]

    // 3. Подставить другое значение вместо изъятого:
    let third = std::mem::replace(&mut v[2], "substitute".to_string());

    let mut vec = vec![1, 2, 3, 4];
    vec.retain(|&x| x%2 == 0);
    assert_eq!(vec, [2, 4]);

    let mut vec = vec![1, 2, 3, 4];
    vec.retain_mut(|x| if *x <= 3 {
        *x += 1;
        true
    } else {
        false
    });
    assert_eq!(vec, [2, 3, 4]);
}

remove(index) - Удаляет и возвращает элемент в указателе положения внутри вектора, перемещая все элементы после него влево.

Минус в том что элементы сдвигаются, это медленно O(n), лучше использовать swap_remove

Удаление элементов вектора (собрать индексы для удаления потом отсортировать индексы по возрастанию и в цикле по ним удаляя элементы из вектора v.remove сдивагать index удаляемого элемента)

fn filter(v:&mut [32]){
    let mut indexes:Vec<usize>=vec![];
    for (pos,value) in v.iter().enumerate(){
         if *value%2!=0{
             indexes.push(pos);
         }
    }
   indexes.sort();
   let mut correct_pos = 0;
   for pos in indexes{
      v.remove(pos-correct_pos);
      correct_pos+=1;
   }
}
fn main(){}

fn main(){
    let mut v = vec![1, 2, 3];

    v.sort_unstable();
    if let Ok(index) = v.binary_search(&value){
      assert_eq!(v.remove(index), 2);
      assert_eq!(v, [1, 3]);
    }
}

splice() Создает итератор сращивания, который заменяет указанный диапазон в векторе с помощью данного итератора

Создает итератор сращивания, который заменяет указанный диапазон в векторе с помощью данного итератора replace_with и выводит удаленные элементы. replace_with не должна быть той же длины, что и диапазон.

Примечание:

  • 1: Диапазон элементов удаляется, даже если итератор не потребляется до конца.
  • 2: Неизвестно, сколько элементов удалено из вектора, если значение Splice просочилось.
  • 3: Входной итератор replace_with потребляется только тогда, когда значение Splice отбрасывается.
  • 4: Это оптимально, если:

Хвост (элементы в векторе после диапазона) пуст, или replace_with дает меньше элементов, чем длина диапазона, или нижняя граница его size_hint() точна. В противном случае выделяется временный вектор, а хвост перемещается дважды.


fn main(){
// заменить в векторе v с 1..3 елементами из new и получить новый вектор с замененными елементами вектора v
    let mut v = vec![11, 12, 13];
    let new = [7, 8];
    let u: Vec<_> = v.splice(1..3, new.iter().cloned()).collect();
    assert_eq!(v, &[11,7, 8]);
    assert_eq!(u, &[12, 13]);
}

drain(1..) - Создает итератор, который удаляет указанный диапазон в векторе и возвращает удаленные элементы

dedup() - Удаляет последовательные повторяющиеся элементы в векторе. Если вектор отсортирован, это удаляет все дубликаты.

dedup_by_key() - Удаляет элемент если удовлетворяет условию предиката и есть дубль, дубли удалит

dedup_by() - Удаляет все, кроме первого из последовательных элементов в векторе, удовлетворяющих заданному соотношению равенства.

Паники, если начальная точка больше конечной точки или конечная точка больше длины вектора


fn main(){
     let mut v = vec![1, 2, 3];
     let u: Vec<_> = v.drain(1..).collect();
     assert_eq!(v, &[1]);
     assert_eq!(u, &[2, 3]);

     v.drain(..);
     assert_eq!(v, &[]);
}


fn main(){
    let mut vec = vec![1, 2, 2, 3, 2];
    vec.sort();
    vec.dedup();
    assert_eq!(vec, [1, 2, 3, 2]);
}


fn main(){
    let mut vec = vec![10, 20, 21, 30, 20];
    // vec.dedup_by_key(|i| *i / 10);//10, 20, 30, 20
    vec.dedup_by_key(|i| true);// 10
}


fn main(){
    let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
    vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
    assert_eq!(vec, ["foo", "bar", "baz", "bar"]);

    let mut s: Vec = Vec::from_iter("aaa    bbb   ccc".chars());
    s.dedup_by(|a, b| a.is_whitespace() && b.is_whitespace());
    let result: String = String::from_iter(s);
    println!("{result}",);
}

clear() - Очищает вектор, удаляя все значения. Не влияет на выделенную емкость


fn main(){
    let mut v = vec![1, 2, 3];
    v.clear();
    assert!(v.is_empty());
}

truncate(2) - Сокращает вектор, сохраняя первые элементы len

resize() - Изменяет размер Vec на месте, так что len равно new_len.

Если new_len больше len, Vec увеличивается на разницу, причем каждый дополнительный слот заполняется значением. Если new_len меньше len, Vec просто усекается.

resize_with<F>(&mut self, new_len: usize, f: F) - Изменяет размеры на Vec месте, так что len равно new_len


fn main(){
    let mut vec = vec![1, 2, 3, 4, 5];
    vec.truncate(2);
    assert_eq!(vec, [1, 2]);
}


fn main(){
    let mut vec = vec!["hello"];
    vec.resize(3, "world");
    assert_eq!(vec, ["hello", "world", "world"]);

    let mut vec = vec![1, 2, 3, 4];
    vec.resize(2, 0);
    assert_eq!(vec, [1, 2]);
}

Изменяет размеры на Vec месте, так что len равно new_len.

Если new_len больше чем len, то Vec увеличивается на разницу, каждый дополнительный слот заполняется результатом вызова закрытия f Если new_len меньше чем len, Vec просто усекается.


fn main(){
    let mut vec = vec![1, 2, 3];
    vec.resize_with(5, Default::default);
    assert_eq!(vec, [1, 2, 3, 0, 0]);

    let mut vec = vec![];
    let mut p = 1;
    vec.resize_with(4, || { p *= 2; p });
    assert_eq!(vec, [2, 4, 8, 16]);
}

extend_from_slice(&mut self, other: &[T]) - Расширяет вектор из среза

extend_from_within<R>(&mut self, src: R) - Копирует в конец свой диапазон

insert(1, 4) - Вставляет элемент в индекс позиции внутри вектора, сдвигая все элементы после него вправо

append() - Перемещает все элементы из вектора в вектор


fn main(){
    let mut vec1 = vec![10,20,30];
    let mut vec2 = vec![2,3];
    let mut vec3 = vec![4,5];
     
    vec1.extend_from_slice(&vec2);
    vec1.extend_from_slice(&vec3);
    println!("{:?}",vec1 );
    assert_eq!(vec1,[10, 20, 30, 2, 3, 4, 5]);
}


fn main(){
    let mut vec = vec![0, 1, 2, 3, 4];
    vec.extend_from_within(2..);
    assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4]);
}


fn main(){
    let mut vec = vec![1, 2, 3];
    vec.insert(1, 4);
    assert_eq!(vec, [1, 4, 2, 3]);
    vec.insert(4, 5);
    assert_eq!(vec, [1, 4, 2, 3, 5])
}


fn main(){
    let mut vec = vec![1, 2, 3];
    let mut vec2 = vec![4, 5, 6];
    vec.append(&mut vec2);
    assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
    assert_eq!(vec2, []);
}

as_slice(&self) -> &[T] - Возвращает срез всего вектора, аналогично &s[..]

as_mut_slice() - Возвращает изменяемый срез всего вектора, аналогично &mut s[..]

leak<'a>(self) -> &'a mut [T] - Потребляет и пропускает Vec, возвращая изменяемую ссылку на содержимое, & 'a mut [T]

split_off(1) - Разделяет коллекцию на две по заданному индексу. Возвращает вновь выделенное Я. self содержит элементы [0, at), а возвращаемое Self содержит элементы [at, len).

method.leak


fn main(){
    use std::io::{self, Write};
    let buffer = vec![1, 2, 3, 5, 8];
    io::sink().write(buffer.as_slice()).unwrap();

    let v:Vec = vec![1,2,3,4,5,6,7,8,9,10];
    select_rand_val2(v.as_slice());
    fn select_rand_val2(slice:&[i32]){}
}


fn main(){
    use std::io::{self, Read};
    let mut buffer = vec![0; 3];
    io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap();
}


fn main(){
    let x = vec![1, 2, 3];
    let static_ref: &'static mut [usize] = x.leak();
    static_ref[0] += 1;
    assert_eq!(static_ref, &[2, 2, 3]);
}


fn main(){
    let mut vec = vec![1,2,3];
    let vec2 = vec.split_off(1);
    assert_eq!(vec, [1]);
    assert_eq!(vec2, [2, 3]);
}

into_boxed_slice(self) -> Box<[T]> Конвертирует с потерей емкости в Box<T>


fn main(){
    let mut vec = Vec::with_capacity(10);
    vec.extend([1, 2, 3]);

    assert_eq!(vec.capacity(), 10);
    let slice = vec.into_boxed_slice();
    assert_eq!(slice.into_vec().capacity(), 3);
}

split_at_spare_mut - Возвращает содержимое вектора в виде части T, а также оставшуюся свободную емкость вектора в виде части MaybeUninit<T>


fn main(){
    // split_at_spare_mut (&mut self) -> (&mut [T] , &mut [ MaybeUninit ])
   //  Возвращает содержимое вектора в виде части T, а также оставшуюся свободную емкость вектора в виде части MaybeUninit

    #![feature(vec_split_at_spare)]

    let mut v = vec![1, 1, 2];

    // Зарезервируйте дополнительное место, достаточное для 10 элементов.
    v.reserve(10);

    let (init, uninit) = v.split_at_spare_mut();
    let sum = init.iter().copied().sum::();

    // Заполните следующие 4 элемента.
    uninit[0].write(sum);
    uninit[1].write(sum * 2);
    uninit[2].write(sum * 3);
    uninit[3].write(sum * 4);

    // Отметьте 4 элемента вектора как инициализированные.
    unsafe {
        let len = v.len();
        v.set_len(len + 4);
    }

    assert_eq!(&v, &[1, 1, 2, 4, 8, 12, 16]);
}

spare_capacity_mut - Возвращает оставшуюся свободную емкость вектора как часть MaybeUninit<T>


fn main(){
    // Выделить вектор достаточно большого размера для 10 элементов.
    let mut v = Vec::with_capacity(10);

    // Заполните первые 3 элемента.
    let uninit = v.spare_capacity_mut();
    uninit[0].write(0);
    uninit[1].write(1);
    uninit[2].write(2);

    // Отметить первые 3 элемента вектора как инициализированные.
    unsafe {
        v.set_len(3);
    }

    assert_eq!(&v, &[0, 1, 2]);
}

Применяется для доступа к части массива/вектора без его копирования.

Имеет тип &[T]/&mut [T]

Они полезны, когда нужно обеспечить безопасный, эффективный доступ к части массива без копирования. Их размер не известен при компиляции

Срез — это ссылка на первый элемент массива, и полем его длины. Т.е. мы можем обойти срез, не проверяя выход за границу.

pub struct Slice<'a, T> {
    ptr: *const T, // указатель на первый элемент
    len: usize,    // количество элементов в срезе
}

Срез строковый &str &string[0..5]

Срез массива &[..]

  • new_uninit_slice()
  • new_uninit_slice_in()
  • new_zeroed_slice() - Создает новый слайс в штучной упаковке с неинициализированным содержимым, при этом память заполняется 0 байтами.
  • new_zeroed_slice_in()
  • try_new_uninit_slice()
  • try_new_zeroed_slice()

new_uninit_slice

Создание


fn main(){
    let mut vector = vec![1, 2, 3, 4, 5, 6, 7, 8];
    let slice:&[i32] = &vector[3..6];
    let slice:&mut [i32] = &mut vector[3..6];
    let slice:&[i32] = vector.as_slice();

    let mut array = [10, 20, 30, 40, 50];
    let slice: &mut [i32] = &mut array[1..4];
}

Преобразует ссылку на T в срез длиной 1 (без копирования)

std::slice::from_mut<T>(s: &mut T) -> &mut [T]

std::slice::from_ref<T>(s: &T) -> &[T]


fn main(){
    let mut s = String::from("...");
    let m_slice:&mut [String] = std::slice::from_mut(&mut s);
    let slice:&[String] = std::slice::from_ref(&s);
}

Deref

Функция принимает любые Vec и [] и &[]

Поскольку эта функция принимает ссылку на срез , ее можно применить как к вектору, так и к массиву.


fn print(n: &[i32]) {
      for elt in n {
            println!("{}", elt);
      }
}
fn main(){
      let v:Vec = vec![1,2,3];
      let a:[i32;3] = [1,2,3];
      print(&v); // работает с векторами
      print(&a); // работает с массивами
      print(&v[..2]); // диапазон
}

include_bytes! - создает &'static [u8; N] из файла байт

include_str! - создает &str из файла байт

macro.include_bytes


fn main(){
    let bytes = include_bytes!("spanish.in");
    assert_eq!(bytes, b"adi\xc3\xb3s\n");
    print!("{}", String::from_utf8_lossy(bytes));
}

Срез slices

Это жирный указатель на массив, это потому, что срез - это не просто указатель на массив, он также содержит количество элементов среза в дополнительном поле длины.

Срез всего массива, жирный указатель, занимает 16 байт. Если мы возьмем указатель на массив, мы получим тонкий указатель, занимающий 8 байт.

arrays-vectors-and-slices-in-rust

Наличие поля длины также можно увидеть в следующем коде, в котором размер slice (&[i32]) составляет 16 байтов (8 для указателя буфера и 8 для поля длины)


fn main(){
    use std::mem::size_of;
    println!("Size of a reference to an i32: {:}", size_of::<&i32>()); // 8
    println!("Size of a slice: {:}", size_of::<&[i32]>()); // 16 (8 для указателя буфера и 8 для поля длины)
}

Из среза в массив и в число

fn main(){
    let var:u64 = 144u64;
    let bytes = var.to_be_bytes();
    let complete:&[u8]=&bytes[..8];
          
    let mut array = [0u8; 8];
    for (&x, p) in complete.iter().zip(array.iter_mut()) {
        *p = x;
    }
    assert_eq!(u64::from_be_bytes(array),var );
}

use std::convert::AsMut;

fn make_array<A, T>(slice: &[T]) -> A
    where A: Sized + Default + AsMut<[T]>,
          T: Copy
{
    let mut a = Default::default();
    // the type cannot be inferred!
    // a.as_mut().copy_from_slice(slice);

    <A as AsMut<[T]>>::as_mut(&mut a).copy_from_slice(slice);
    a
}
fn main(){
    let original = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let a: [u8; 4] = make_array(&original[0..4]);
    println!("{:?}", a);// [1, 2, 3, 4]
}

У [] тип &'static [], пустые срезы можно извлекать из воздуха

fn as_slice<'a>(xs: Option<&'a Vec<i32>>) -> &'a [i32] {
    match xs {
        Some(xs) => xs.as_slice(),
        None => &[],
    }
}
fn main(){}

Автоматическое приведение типов для гибкого API

impl<T> Trait for [T]

sizedness-in-rust.md#unsized-types


trait Trait {
    fn method(&self) {}
}
impl Trait for str {
    // теперь можно вызвать "метод" на
    // 1) str or
    // 2) String since String: Deref
}
impl Trait for [T] {
    // теперь можно вызвать "метод" на
    // 1) any &[T]
    // 2) any U where U: Deref, e.g. Vec
    // 3) [T; N] for any N, since [T; N]: Unsize<[T]>
}
fn str_fun(s: &str) {}
fn slice_fun(s: &[T]) {}

fn main() {
    let str_slice: &str = "str slice";
    let string: String = "string".to_owned();

    // function args
    str_fun(str_slice);
    str_fun(&string); // deref приведение

    // method calls
    str_slice.method();
    string.method(); // deref приведение

    let slice: &[i32] = &[1];
    let three_array: [i32; 3] = [1, 2, 3];
    let vec: Vec = vec![1];

    // function args
    slice_fun(slice);
    slice_fun(&vec); // deref приведение
    slice_fun(&three_array); // безразмерное приведение

    // method calls
    slice.method();
    vec.method(); // deref приведение
    three_array.method(); // безразмерное приведение
}

Это не срез, последовательность элементов одного типа T расположенных в памяти один за другом , имеющая фиксированный размер в момент компиляции и не изменяемый по умолчанию. Память для массивов выделяется в стеке

Массив находится в стеке, так как на момент компиляции известен его размер. Изменить его значения можно но изменить его длину нельзя.

Прямое обращение по индексу arr[i] в Rust всегда включает проверку границ во время выполнения (runtime bounds checking). Это фундаментальное отличие Rust от C/C++, где такая проверка отсутствует.

crate arrayvec Массивы, которые ТОЛЬКО размещаются в стеке с фиксированной емкостью

crate smallvec Массивы, которые размещаются в стеке с возможностью возврата в кучу в случае превышения фиксированной емкости стека.

crate tinyvec Стек выделяет массивы в 100% безопасном коде Rust, но требует элементов для реализации свойства Default.

когда использовать векторы, а когда использовать массивы

Вы можете задаться вопросом, когда использовать векторы, а когда использовать массивы. Векторы более гибкие. У вас может возникнуть соблазн обратиться к массивам для повышения производительности. На первый взгляд это кажется логичным, поскольку они хранятся в стеке. Доступ к стеку будет быстрее, поскольку размеры памяти можно вычислить во время компиляции, что упрощает выделение и освобождение по сравнению с кучей.

Однако, поскольку он находится в стеке, он не может пережить область, в которой он выделен. Перемещение вектора потребует перемещения указателя. Однако перемещение массива требует копирования всего массива. Поэтому копирование массивов фиксированного размера обходится дороже, чем перемещение вектора. Если у вас есть небольшой объем данных, которые вам нужны только в небольшой области, и вы знаете размер данных, то обращение к массиву имеет смысл. Однако, если вы собираетесь перемещать данные, даже если вы знаете размер данных, использование векторов является лучшим выбором.

Создание


fn main(){
    let a:[i32;6]=[1;6];// заполнение массива, 6 элементов, все единицы [1,1,1,1,1,1]

    let one = [1,2,3];
    let two: [u8; 3] = [1,2,3];
    let arrays = [one, two];
    let array: [i32; _] = std::array::from_fn(|i| i); // [0, 1, 2, 3, 4]
    let arr: [String; _] = array::from_fn(|i| format!("Element {}", i)); // ["Element 0", "Element 1", ...]

    // изменяемый
    let mut arr:[i32;20] = [7; 20];
    arr[1] = 9;

    use std::borrow::Borrow;
    // AsRef Borrow Default From
    let arr:[i32;32] = Default::default();// от 1 до 32
    // let arr:[i32;33] = Default::default();// Нет имплементации
    let arr:[i32;3] = From::from((1,2,3));
    let slice:&[i32] = arr.as_ref();
    let slice:&[i32] = arr.borrow();
}

Из Vec<> в массив

From<[T; N]>

struct.Vec


fn main(){
    let buf:Vec = vec![1;8];
    let mut arr: [u8; 8] = buf[..8].try_into().unwrap();
    let mut arr: [u8; 8] = TryFrom::try_from(buf).unwrap();
    let mut arr: [u8; 8] = <[u8; 8]>::try_from(buf).unwrap();

     или     
    let [b1,b2,b3,b4,b5,b6,b7,b8,..] = buf[..] else { todo!() };
    let mut arr:[u8;8] = From::from((b1,b2,b3,b4,b5,b6,b7,b8));

     или      
    const size:usize = 8;
    let mut arr:[u8;size]= todo!();
    for (i,v) in buf.iter().take(size).enumerate(){
          arr[i]=*v;
    }
}


use std::convert::TryInto;
fn main(){
    const N:usize = 3;
    let v:Vec = vec!["..".to_string()];
    let arr:[String;N] = v.try_into().unwrap_or_else(|v: Vec| panic!("Expected a Vec of length {} but it was {}", N, v.len()));
    for item in arr.iter() {
        let x: &String = item;
        println!("{x}");
    }
}

Массив реализует Copy и Clone


fn main(){
    let arr_1: [i32; 3] = [1; 3];
    let arr_2 = arr_1; // Copy
    println!("{:?} {:?}",arr_1,arr_2);// 2 массив скопированы
}

const fn функции

Применение const fn

Один из них - убедиться, что компилятор может предварительно вычислить некоторые величины во время компиляции, когда это необходимо для хорошей производительности во время выполнения. Другой способ заключается в получении величин, которые должны быть известны во время компиляции, таких как длина массивов.


const fn get_size(x: usize) -> usize {
    x * 2usize
}
fn main(){
    const TEN: usize = get_size(5usize); // Это будет выполнено во время компиляции
    let arr:[i32;TEN] = [1,2,3,4,5,6,7,8,9,10];
    assert_eq!(10usize, TEN);
}

Массив передача по mut ссылке


fn no_mut_arr(a:&[i32;3]){
    //a[0] = 9; //ошибка изменять запрещенно
    assert_eq!(a[0],1);
}

// чтоб изменять массив его надо передать и принять как mut
fn mut_arr(a:&mut [i32;3]){
    a[0] = 9;
}

fn main() {
    let mut arr =[1,2,3];
    no_mut_arr(& arr);
    
    mut_arr(&mut arr);
    assert_eq!(arr[0],9);
}

Methods []

  • as_ascii
  • as_ascii_unchecked
  • as_mut_slice
  • as_slice
  • each_mut
  • each_ref
  • map
  • try_map
  • split_array_ref
  • split_array_mut
  • rsplit_array_mut
  • rsplit_array_ref
  • transpose
  • zip

Function

  • std::array::from_fn

std::array::from_fn используется для создания массива фиксированного размера ([T; N]), где каждый элемент генерируется с помощью замыкания.

Создание массива случайных чисел (в сочетании с rand):


use std::array;
use rand::Rng;

fn main() {
    let mut rng = rand::thread_rng();
    let random_array: [i32;10] = array::from_fn(|_| rng.gen_range(1..=10));
    println!("{:?}", random_array); // Пример: [3, 7, 1, 10, 5]
// ------------------------------ 
    let arr:[&str;10] = array::from_fn(|i| format!("Element {}", i)); // ["Element 0", "Element 1", ...]
}

as_slice - Возвращает срез, содержащий весь массив. Эквивалентно &s[..]

as_mut_slice


fn main(){
    let mut arr:[i32;3] = From::from((1,2,3));
    let slice:&[i32] = arr.as_slice();
    let slice:&mut [i32] = arr.as_mut_slice();
}

as_ascii - Преобразует этот массив байтов в массив символов ASCII

as_ascii_unchecked


fn main(){
#![feature(ascii_char)]
#![feature(const_option)]
    const HEX_DIGITS: [std::ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap();
    assert_eq!(HEX_DIGITS[1].as_str(), "1");
    assert_eq!(HEX_DIGITS[10].as_str(), "a");
}

Заимствует каждый изменяемый элемент и возвращает массив изменяемых ссылок

each_mut(&mut self) -> [&mut T; N]

each_ref(&self) -> [&T; N]


#![feature(array_methods)]
fn main() {
    let mut arr:[String;3] = ["hello".to_string(),"".to_string(),"".to_string()];
    let arr_refs: [&mut String; 3] = arr.each_mut();
    *arr_refs[0] = "bye".to_string();
    assert_eq!(arr_refs, [&mut "bye".to_string(),&"".to_string(),&"".to_string()]);
    assert_eq!(arr, ["bye".to_string(),"".to_string(),"".to_string()]);
}

Run:

$ cargo +nightly run

map<F, U>(self, f: F) -> [U; N] - трансформирует массив в новый массив

try_map


fn main(){
    let x:[i32;3] = [1, 2, 3];
    let mut temp = 0;
    let y:[i32;3] = x.map(|v| { temp += 1; v * temp });
    assert_eq!(y, [1, 4, 9]);

    let x:[&str;4] = ["Ferris", "Bueller's", "Day", "Off"];
    let y:[usize;4] = x.map(|v| v.len());
    assert_eq!(y, [6, 9, 3, 3]);
}

Разделяет изменяемую ссылку на массив на две по индексу

  • rsplit_array_mut
  • rsplit_array_ref
  • split_array_mut
  • split_array_ref

fn main(){
    #![feature(split_array)]

    let mut v = [1, 0, 3, 0, 5, 6];
    let (left, right) = v.split_array_mut::<2>();
    assert_eq!(left, &mut [1, 0][..]);
    assert_eq!(right, &mut [3, 0, 5, 6]);
    left[1] = 2;
    right[1] = 4;
    assert_eq!(v, [1, 2, 3, 4, 5, 6]);
}

zip<U>(self, rhs: [U; N]) -> [(T, U); N] «Сжимает» два массива в один массив пар


fn main(){
    #![feature(array_zip)]
    let x = [1, 2, 3];
    let y = [4, 5, 6];
    let z:[(i32,i32);3] = x.zip(y);
    assert_eq!(z, [(1, 4), (2, 5), (3, 6)]);
}
  • Create:
  • fill() - Заполняет self элементами путем клонирования value
  • fill_with() - Заполняет себя элементами, возвращаемыми путем многократного вызова закрытия.
  • to_vec() - Копирует self в новый Vec
  • to_vec_in() - Копирует self в новый Vec с распределителем
  • repeat() - Создает вектор, повторяя срез n раз.
  • concat() - Собирает фрагмент T в одно значение Self::Output
  • join() - Собирает фрагмент T в одно значение Self::Output, помещая между ними заданный разделитель
  • clone_from_slice() - Копирует элементы из src в self
  • copy_from_slice() - Копирует все элементы из src в self, используя memcpy
  • copy_within() - Копирует элементы из одной части среза в другую часть самого себя

  • iter() - Возвращает итератор по срезу
  • iter_mut()

  • Index:
  • last(), last_mut() - Возвращает последний элемент среза
  • get(), get_mut() - Возвращает ссылку на элемент или подсрез в зависимости от типа индекса.
  • get_unchecked() - Возвращает ссылку на элемент или подсрез без проверки границ
  • get_unchecked_mut()
  • first(), first_mut() - Возвращает первый элемент фрагмента
  • first_chunk(), first_chunk_mut() - Возвращает первые N элементов среза
  • last_chunk(), last_chunk_mut()
  • get_many_mut() - Возвращает изменяемые ссылки сразу на множество индексов.
  • get_many_unchecked_mut()

  • Contains:
  • len() - количество ел
  • is_empty() - проверка на пустоту
  • contains() - проверка существования значения
  • as_bytes() - Просматривает этот фрагмент символов ASCII как фрагмент из u8 байтов
  • starts_with() - Возвращает, truе если needle является префиксом фрагмента
  • ends_with() - Возвращает, true если needle является суффиксом фрагмента.
  • binary_search() - Бинарный поиск в отсортированном срезе данного элемента
  • binary_search_by() - Двоичный поиск в этом отсортированном срезе компаратором
  • binary_search_by_key() - Двоичный поиск в отсортированном фрагменте функцией ключа.
  • is_ascii() - Проверяет, все ли байты в этом фрагменте находятся в диапазоне ASCII
  • eq_ignore_ascii_case() - Проверяет, совпадают ли два фрагмента без учета регистра в кодировке ASCII
  • is_sorted()/is_sorted_by()/ is_sorted_by_key() - Проверяет, отсортированы ли элементы этого фрагмента.

  • Ptr:
  • into_raw_parts() - Разкладывает Vec<T> на необработанные компоненты (ptr, len, cap).
  • into_raw_parts_with_alloc()
  • from_raw_parts() - Создает Vec<T, A> непосредственно из (ptr, len, cap)
  • from_raw_parts_in() - Создает Vec<T, A> непосредственно из (ptr, len, cap,alloc)
  • as_ptr() - Возвращает *const T необработанный указатель на буфер среза.
  • as_mut_ptr() - Возвращает *mut T небезопасный изменяемый указатель на буфер среза
  • as_ptr_range() - Возвращает два необработанных указателя, охватывающих срез
  • as_mut_ptr_range()

  • Sort:
  • sort() - Сортирует последовательность
  • sort_by() - Сортирует фрагмент с помощью функции компаратора
  • sort_by_key() - Сортирует фрагмент с функцией извлечения ключа
  • sort_by_cached_key() - Сортирует фрагмент с функцией извлечения ключа
  • sort_unstable() - Сортирует фрагмент, но не может сохранять порядок равных элементов.
  • sort_unstable_by()
  • sort_unstable_by_key() - Сортирует фрагмент с помощью функции извлечения ключа
  • sort_floats() - Сортирует последовательность вещественных чисел

  • Split:
  • partition_point() - Возвращает индекс точки раздела в соответствии с заданным предикатом
  • split(), split_mut() - Возвращает итератор по фрагментам, разделенным соответствующими элементами pred
  • split_array_mut() - Делит один изменяемый срез на массив и оставшийся срез по индексу.
  • split_array_ref() - Делит один срез на массив и оставшийся срез по индексу с конца.
  • split_first(), split_first_mut() - Возвращает первый и все остальные элементы среза
  • split_last(), split_last_mut() - Возвращает последний и все остальные элементы среза
  • split_first_chunk(), split_first_chunk_mut() - Возвращает первые N элементов среза и остаток или None, если в нем меньше N элементов.
  • split_last_chunk(), split_last_chunk_mut()
  • split_inclusive(), split_inclusive_mut() - Итератор по фрагментам, разделенным соответствующими элементами pred
  • split_at(), split_at_mut() - Делит один фрагмент на два по индексу.
  • split_at_mut_unchecked(), split_at_unchecked()**
  • rsplit_array_mut() - Делит один изменяемый срез на массив и оставшийся срез по индексу с конца.
  • rsplit_array_ref()
  • rsplit(), rsplit_mut() - Возвращает итератор для фрагментов, разделенных соответствующими элементами pred
  • splitn(), splitn_mut() - Возвращает итератор по фрагментам, разделенным соответствующими элементами pred
  • rsplitn(), rsplitn_mut() - Возвращает итератор по фрагментам, разделенным элементами, которые совпадают
  • windows() - Возвращает итератор по всем смежным окнам длины size
  • array_windows() - Возвращает итератор по перекрывающимся окнам N элементов среза
  • chunks(), chunks_mut() - Возвращает итератор по chunk_size элементам среза за раз
  • chunks_exact(), chunks_exact_mut() - Возвращает итератор по chunk_size элементам среза за раз
  • rchunks(), rchunks_mut() - Возвращает итератор по chunk_size элементам среза за раз
  • rchunks_exact(), rchunks_exact_mut() - Возвращает итератор по chunk_size элементам среза за раз
  • as_rchunks(), as_rchunks_mut() - Разбивает срез на срез массивов из N элементов
  • as_chunks_unchecked(), as_chunks_unchecked_mut() - Разбивает срез на срез массивов из N элементов, предполагая, что остатка нет.
  • as_chunks(), as_chunks_mut() - Разделяет срез на срез N массивов -элементов
  • array_chunks(), array_chunks_mut() - Возвращает итератор по N элементам среза за раз
  • as_simd(), as_simd_mut() - Разделите срез по префиксу, середину выровненных SIMD-типов и суффикс.
  • group_by(), group_by_mut() - группирует по функции сравнения
  • Change:
  • escape_ascii() - Возвращает итератор, который создает экранированную версию этого фрагмента, обрабатывая ее как строку ASCII
  • swap() - Меняет местами два элемента в срезе
  • swap_with_slice() - Меняет местами все элементы на self те, что есть other
  • swap_unchecked() - Меняет местами два элемента в срезе без проверки границ.
  • reverse() - Изменяет порядок элементов в срезе на место
  • select_nth_unstable() - Измените порядок среза так, чтобы элемент находился index
  • select_nth_unstable_by() - Измените порядок среза функцией комп. так, чтобы элемент находился index
  • select_nth_unstable_by_key() - Измените порядок среза с помощью функции извлечения ключа
  • rotate_left() - Поворачивает фрагмент на месте
  • rotate_right() - Поворачивает фрагмент на месте
  • strip_prefix() - Возвращает фрагмент с удаленным префиксом
  • strip_suffix() - Возвращает фрагмент с удаленным суффиксом.
  • align_to(), align_to_mut() - Преобразуйте срез в срез другого типа, сохраняя выравнивание типов.
  • make_ascii_uppercase() - Преобразует этот фрагмент в его эквивалент в верхнем регистре ASCII на месте
  • make_ascii_lowercase()
  • to_ascii_uppercase() - Возвращает вектор, содержащий копию этого фрагмента в верхнем регистре ASCII
  • to_ascii_lowercase() - Возвращает вектор, содержащий копию этого фрагмента в нижнем регистре ASCII
  • as_ascii() - Преобразует этот фрагмент байтов в фрагмент символов ASCII
  • as_ascii_unchecked()
  • partition_dedup() - Перемещает все последовательные повторяющиеся элементы в конец среза
  • partition_dedup_by()
  • partition_dedup_by_key()
  • flatten(), flatten_mut() - Выравнивает вложенный массив из &[[T; N]] в &[T]
  • partition_dedup() - Перемещает все последовательные элементы, кроме первого, в конец среза
  • partition_dedup_by()
  • partition_dedup_by_key()
  • take(), take_mut() - Удаляет подсрез, соответствующий заданному диапазону, и возвращает ссылку на него.
  • take_first(), take_first_mut()
  • take_last(), take_last_mut()

len()

is_empty()


fn main(){
    let arr = [10, 40, 30];
    assert_eq!(arr.len(), 3);
    assert!(!arr.is_empty()); 
}

x.iter(), iter_mut() Возвращает итератор над срезом.


fn main(){
    let x = &mut [1, 2, 4];
    for elem in x.iter_mut() {
        *elem += 2;
    }
    assert_eq!(x, &[3, 4, 6]);
// --------------------------------
    let mut value:[i32;5] = [1,2,3,4,5];
    let r:i32 = value.iter_mut().filter(|x| **x % 2 == 0).map(|v|*v*2).sum();
}
  • fill() - Заполняет Vec элементами путем клонирования value

  • fill_with() - Заполняет себя элементами, возвращаемыми путем многократного вызова закрытия.

  • repeat() - Создает вектор, повторяя срез n раз.

  • to_vec() Копирует себя в новый Vec

  • concat<Item>(&self) - Конкатенирует в одно значение

  • join() - Сливает два массива через соединитель

  • clone_from_slice() - Клонирует элементы из src в себя. Количество элементов для переноса должна быть равна длине приемника. Если src реализует Copy, это может быть более эффективным для использования copy_from_slice.

  • copy_within() - Копирует элементы из одной части среза в другую часть самого себя

concat

copy_within


fn main(){
    let mut buf = vec![0; 10];
    buf.fill(1); // [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    assert_eq!(buf, vec![1; 10]);
}


fn main(){
    let mut buf = vec![1; 10];
    buf.fill_with(Default::default); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    assert_eq!(buf, vec![0; 10]);
}


fn main(){
    let arr = [1, 2, 3];
    let v:Vec = arr.repeat(2);
    assert_eq!(v, vec![1, 2, 3, 1, 2, 3]);
}


fn main(){
    let arr:[i32;3] = [1, 2, 3];
    let v:Vec = (&arr).to_vec();
    let v:Vec = arr.to_vec();
}


fn main(){
    assert_eq!(["hello", "world"].concat(), "helloworld");
    assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
}


fn main(){
    assert_eq!(["hello", "world"].join(" "), "hello world");
    assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
    assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]);
}


fn main(){
    let src = [1, 2, 3, 4];
    let mut dst = [0, 0];
    dst.clone_from_slice(&src[2..]);

    assert_eq!(src, [1, 2, 3, 4]);
    assert_eq!(dst, [3, 4]);
     
    let raw: &[u8] ;   
    let mut array = [0u8; 8];
    array.clone_from_slice(raw);
    u64::from_be_bytes(array)
}


fn main(){
    let mut bytes = *b"Hello, World!";
    bytes.copy_within(0..5, 7);
    assert_eq!(&bytes, b"Hello, Hello!");
}
  • get(0..2) - Возвращает ссылку на элемент или объект в зависимости от типа индекса.

  • get_mut(1) - Возвращает изменчивую ссылку

    Если задана позиция, возвращается ссылка на элемент в этой позиции или None, если она выходит за пределы. Если задан диапазон, возвращает подсечку, соответствующую этому диапазону, или None, если она выходит за пределы.

    Без проверки границ массива в небезопасном режиме

  • unsafe fn get_unchecked() - Возвращает ссылку на элемент или объект в зависимости от типа индекса.

  • unsafe fn get_unchecked_mut() - Возвращает ссылку на элемент без проверки границ.

  • first()

  • first_mut() - Возвращает первые элемент

  • last()

  • last_mut() - Возвращает последний элемент среза или None, если он пуст.


fn main(){
    let v = [10, 40, 30];
    assert_eq!(Some(&40), v.get(1));
    assert_eq!(Some(&[10, 40][..]), v.get(0..2));
    assert_eq!(None, v.get(3));
    assert_eq!(None, v.get(0..4));
}


fn main(){
    let x = &mut [0, 55, 2];
    if let Some(elem) = x.get_mut(55) {
        *elem = 42;
    }
    assert_eq!(x, &[0, 42, 2])
}


fn main(){
    let x = &[1, 2, 4];
    unsafe {
        assert_eq!(x.get_unchecked(1), &2);
    }
}


fn main(){
    let x = &mut [1, 2, 4];
    unsafe {
        let elem = x.get_unchecked_mut(1);
        *elem = 13;
    }
    assert_eq!(x, &[1, 13, 4]);
}


fn main(){
    let x = &mut [0, 1, 2];
    if let Some(first) = x.first_mut() {
        *first = 5;
    }
    assert_eq!(x, &[5, 1, 2]);
}


fn main(){
    let x = &mut [0, 1, 2];
    if let Some(last) = x.last_mut() {
        *last = 10;
    }
    assert_eq!(x, &[0, 1, 10]);
}
  • get_many_mut() - Возвращает изменяемые ссылки сразу на множество индексов.
  • get_many_unchecked_mut()

fn main(){
    #![feature(get_many_mut)]
    let v = &mut [1, 2, 3];
    if let Ok([a, b]) = v.get_many_mut([0, 2]) {
        *a = 413;
        *b = 612;
    }
    assert_eq!(v, &[413, 2, 612]);
}
  • contains() - Возвращает true, если срез содержит элемент с заданным значением.
  • as_bytes() - Просматривает этот фрагмент символов ASCII как фрагмент из u8 байтов
  • ends_with()
  • starts_with() - Возвращает true если срез начинается или заканчивается значением
  • is_ascii - Проверяет, находятся ли все байты в этом сегменте в пределах диапазона ASCII
  • eq_ignore_ascii_case() - Проверяет, что два сегмента - это ASCII-регистр, нечувствительный к регистру. То же, что и to_ascii_lowercase (a) == to_ascii_lowercase (b), но без выделения и копирования временных рядов.

fn main(){
    let v = [10, 40, 30];
    assert!(v.contains(&30));
    assert!(!v.contains(&50));
}


fn main(){
    let v = [10, 40, 30];
    assert!(v.starts_with(&[10]));
    assert!(v.starts_with(&[10, 40]));
    assert!(!v.starts_with(&[50]));
}


fn main(){
    let  s = String::from("Привет");
    unsafe{
        let bytes =  s.as_bytes();
        assert!(!bytes.is_ascii());  
    }
}


fn main(){
    let mut bytes = *b"Hello";
    assert!(bytes.eq_ignore_ascii_case(&[72, 101, 108, 108, 111]));
}
  • binary_search() - Двоичный поиск выполняет этот отсортированный срез для данного элемента.

    Если значение найдено, возвращается Ok, содержащее индекс соответствующего элемента; если значение не найдено, возвращается Err, содержащий индекс, в который может быть вставлен соответствующий элемент, сохраняя отсортированный порядок.

  • binary_search_by() - Двоичный поиск выполняет этот отсортированный срез с помощью функции компаратора. «Меньше», «Равно» или «Больше желаемой цели». Аналогичен возврату binary_search

  • binary_search_by_key() - Двоичный поиск выполняет этот отсортированный срез с функцией извлечения ключа. Предполагается, что срез сортируется по ключу, например, с помощью sort_by_key, используя ту же функцию извлечения ключа. Аналогичен возврату binary_search


fn main(){
    let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];

    assert_eq!(s.binary_search(&13),  Ok(9));
    assert_eq!(s.binary_search(&4),   Err(7));
    assert_eq!(s.binary_search(&100), Err(13));
    let r = s.binary_search(&1);
    assert!(match r { Ok(1...4) => true, _ => false, });
}


fn main(){
    let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];

    let seek = 13;
    assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
    let seek = 4;
    assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
    let seek = 100;
    assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
    let seek = 1;
    let r = s.binary_search_by(|probe| probe.cmp(&seek));
    assert!(match r { Ok(1...4) => true, _ => false, });
}


fn main(){
    let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
             (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
             (1, 21), (2, 34), (4, 55)];

    assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b),  Ok(9));
    assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b),   Err(7));
    assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13));
    let r = s.binary_search_by_key(&1, |&(a,b)| b);
    assert!(match r { Ok(1...4) => true, _ => false, });// может соответствовать любой позиции в [1, 4]
}

fn main(){
    let mut v:Vec<(i32,String)> = vec![(3,String::from("3")),(4,String::from("4"))];
    v.sort_unstable()
    if let Ok(index) = v.binary_search_by_key(&4, |&(a,_)| a){
        v.remove(index);
    }
    println!("{:?}",v );// [(3, "3")]
}
  • swap(1, 3) - Поменяет два элемента на срезе.
  • swap_with_slice() - перемещает все элементы в себя. Количество элементов для переноса должна быть равна длине приемника.
  • reverse() - Изменяет порядок элементов в срезе, на месте.
  • strip_prefix() - Возвращает фрагмент с удаленным префиксом
  • strip_suffix() - Возвращает фрагмент с удаленным суффиксом.
  • align_to() - Преобразуйте срез в срез другого типа, сохраняя выравнивание типов.
  • align_to_mut()

strip_prefix

align_to


fn main(){
    //reverse_array 
     
    let mut arr = vec![1,2,3,4,5];
    let mut first: usize = 0;
    let mut last: usize = arr.len()-1;
    
    while first < last {
        // inplace swap  
        /*
        arr[last] = arr[first] ^ arr[last];  
        arr[first] = arr[first] ^ arr[last];  
        arr[last] = arr[first] ^ arr[last]; 
        */
        // безопасный вариант через swap
        arr.swap(first, last);
        
        first+=1;
        last-=1;
    }
    println!("{:?}",arr);// [5, 4, 3, 2, 1]
}


fn main(){
    let mut to = [0, 0];
    let mut from = [1, 2, 3, 4];
    to.swap_with_slice(&mut from[2..]); // количество 2 равно длине приемника
    assert_eq!(to, [3, 4]);
    assert_eq!(from, [1, 2, 0, 0]);
}


fn main(){
    let mut v = [1, 2, 3];
    v.reverse();
    assert!(v == [3, 2, 1]);
}


fn main(){
    let v = &[10, 40, 30];
    assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..]));
    assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..]));
    assert_eq!(v.strip_prefix(&[50]), None);
    assert_eq!(v.strip_prefix(&[10, 50]), None);
    let prefix : &str = "he";
    assert_eq!(b"hello".strip_prefix(prefix.as_bytes()),Some(b"llo".as_ref()));
}


fn main(){
    unsafe {
        let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
        let (prefix, shorts, suffix) = bytes.align_to::();
        let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
        let (prefix, shorts, suffix) = bytes.align_to_mut::();
    }
}
  • select_nth_unstable_by_key() - Измените порядок среза с помощью функции извлечения ключа

  • select_nth_unstable()

  • select_nth_unstable_by() Измените порядок среза так, чтобы элемент по index находился в окончательной отсортированной позиции.

  • rotate_left() Поворачивает срез на место таким образом, что первые средние элементы среза перемещаются в конец, а последние элементы self.len () - mid перемещаются вперед. После вызова rotate_left элемент ранее в середине индекса станет первым элементом в срезе.

  • rotate_right()

select_nth_unstable


fn main(){
    let mut v = [-5i32, 4, 1, -3, 2];

    // Find the median
    v.select_nth_unstable(2);

    // Мы гарантируем, что срез будет одним из следующих, в зависимости от того, как мы сортируем
    // по указанному индексу.
    assert!(v == [-3, -5, 1, 2, 4] ||
                v == [-5, -3, 1, 2, 4] ||
                v == [-3, -5, 1, 4, 2] ||
                v == [-5, -3, 1, 4, 2]);
}


fn main(){
    let mut v = [-5i32, 4, 1, -3, 2];
    // Найдите медиану, как если бы срез был отсортирован в порядке убывания.
    v.select_nth_unstable_by(2, |a, b| b.cmp(a));
    assert!(v == [2, 4, 1, -5, -3] ||
                v == [2, 4, 1, -3, -5] ||
                v == [4, 2, 1, -5, -3] ||
                v == [4, 2, 1, -3, -5]);
}


fn main(){
    let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
    a.rotate_left(2);
    assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']);
    Rotating a subslice:

    let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
    a[1..5].rotate_left(1);
    assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']);
}


fn main(){
    let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
    a.rotate_right(2);
    assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']);
}
  • make_ascii_uppercase(&mut self) - Преобразует этот фрагмент в эквивалент ASCII верхнего регистра на месте. ASCII буквы «от» до «z» отображаются в «A» на «Z», но буквы без ASCII не изменяются. Чтобы вернуть новое верхнее значение без изменения существующего, используйте to_ascii_uppercase.

  • make_ascii_lowercase() - Преобразует этот фрагмент в эквивалент ASCII нижнего регистра на месте, чтобы вернуть новое нижнее значение без изменения существующего, используйте to_ascii_lowercase.

  • to_ascii_lowercase(&self) -> Vec<u8> Возвращает вектор, содержащий копию этого фрагмента, где каждый байт сопоставляется с его эквивалентом в нижнем регистре ASCII. ASCII буквы «A» на «Z» отображаются в «a» на «z», но буквы без ASCII не изменяются. Чтобы ввести значение на месте, используйте make_ascii_lowercase

  • to_ascii_uppercase(&self) -> Vec<u8>

Возвращает вектор, содержащий копию этого среза, где каждый байт сопоставляется с его эквивалентом верхнего регистра ASCII. ASCII буквы «от» до «z» отображаются в «A» на «Z», но буквы без ASCII не изменяются. Чтобы загладить значение на месте, используйте make_ascii_uppercase.


fn main(){
    let mut bytes = *b"hello";
    bytes.make_ascii_uppercase();
    if let Ok(result)=std::str::from_utf8(&bytes){
        assert_eq!(result,"HELLO");
    }
}


fn main(){
    let mut bytes = *b"HELLO";
    bytes.make_ascii_lowercase();
    if let Ok(result)=std::str::from_utf8(&bytes){
        assert_eq!(result,"hello");
    }
}


fn main(){
    let mut bytes = *b"HELLO";
    let to_lower:Vec = bytes.to_ascii_lowercase();
    if let Ok(result)=std::str::from_utf8(&to_lower){
        assert_eq!(result,"hello");
    }
}


fn main(){
    let mut bytes = *b"hello";
    let to_upper:Vec = bytes.to_ascii_uppercase();
    if let Ok(result)=std::str::from_utf8(&to_upper){
        assert_eq!(result,"HELLO");
    }
}
  • as_ascii() - Преобразует этот фрагмент байтов в фрагмент символов ASCII
  • as_ascii_unchecked()

method.as_ascii


fn main(){
    let mut a:Vec = vec![b'h',b'e'];
    let s = a.as_ascii();
    print!("{:?}",s);
}

sort f32

the trait std::cmp::Ord is not implemented for f32

sort_floats() - Сортирует последовательность вещественных чисел


fn main(){
    let mut v:Vec=vec![1.0,4.0,3.0];
    //v.sort();// the trait `std::cmp::Ord` is not implemented for `f32`
    v.sort_by(|a,b|a.partial_cmp(b).unwrap()); если нет std::f64::NAN иначе ошибка
    println!("{:?}",v);
}


fn main(){
    #![feature(sort_floats)]
    let mut v = [2.6, -5e-8, f32::NAN, 8.29, f32::INFINITY, -1.0, 0.0, -f32::INFINITY, -0.0];
    v.sort_floats();
    let sorted = [-f32::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f32::INFINITY, f32::NAN];
    assert_eq!(&v[..8], &sorted[..8]);
    assert!(v[8].is_nan());
}

par_sort() от rayon параллельная сортировка

crate rayon

rust-how-to-sort-a-vector


use rayon::prelude::*;
fn main(){
    let mut v = vec![3, 2, 90, 78, 64, 32, 1, -10, 10, 10000];
    v.par_sort();
    println!("{:?}", v);
}
  • sort() - Сортирует последовательность.

Этот тип является стабильным (т. е. Не меняет порядок равных элементов) и O (n log n) в худшем случае. Когда применимо, неустойчивая сортировка предпочтительнее, потому что она обычно быстрее, чем стабильная сортировка, и она не выделяет вспомогательную память. См. sort_unstable.

  • sort_unstable() - Сортирует последовательность, но может не сохранять порядок равных элементов.

  • sort_unstable_by() - Сортирует срез с помощью функции компаратора, но может не сохранять порядок равных элементов.

  • sort_unstable_by_key() - Сортирует срез с функцией извлечения ключа, но может не сохранять порядок равных элементов.

  • sort_by_key() - Сортирует срез с функцией извлечения ключа. Этот тип стабилен (т. е. Не меняет порядок равных элементов) и O (m n log (m n)) в худшем случае, где ключевая функция - O (m). Предпочтительней sort_unstable_by_key. Для дорогих функций клавиш (например, функций, которые не являются простыми обращениями к свойствам или базовыми операциями), sort_by_cached_key вероятно, будет значительно быстрее, так как он не пересчитывает ключи элементов.


fn main(){
    let mut a:Vec = vec![1,2,3];
    let mut a:[i32;3] = [1,2,3];
    a.sort();
}


fn main(){
    let mut v = [-5, 4, 1, -3, 2];
    v.sort_unstable();
    assert!(v == [-5, -3, 1, 2, 4]);
        
    let mut v:Vec<&str> = vec!["-5", "4","2","-10"];
    v.sort_unstable();
    println!("{:?}",v);// ["-10", "-5", "2", "4"]
}


fn main(){
    let mut v = [5, 4, 1, 3, 2];
    v.sort_unstable_by(|a, b| a.cmp(b));
    assert!(v == [1, 2, 3, 4, 5]);

    // reverse sorting
    v.sort_unstable_by(|a, b| b.cmp(a));
    assert!(v == [5, 4, 3, 2, 1]);
}


fn main(){
    let mut v = [-5i32, 4, 1, -3, 2];
    v.sort_unstable_by_key(|k| k.abs());
    assert!(v == [1, 2, -3, 4, -5]);
}


fn main(){
    let mut v = [-5i32, 4, 1, -3, 2];

    v.sort_by_key(|k| k.abs());
    assert!(v == [1, 2, -3, 4, -5]);
}

pub fn sort_by_cached_key<K, F>(&mut self, f: F)

Сортирует срез с помощью функции извлечения ключа. Во время сортировки ключевая функция вызывается только один раз для каждого элемента. Для простых ключевых функций (например, функций, которые имеют доступ к свойствам или основные операции), sort_by_key скорее всего, это будет быстрее.


fn main(){
    let mut v = [-5i32, 4, 32, -3, 2];
    v.sort_by_cached_key(|k| k.to_string());
    assert!(v == [-3, -5, 2, 32, 4]);
}

sort_by() - Сортирует срез с помощью функции компаратора.

Этот тип является стабильным (т. е. Не меняет порядок равных элементов) и O (n log n) в худшем случае. Предпочтительней sort_unstable_by


fn main(){
    let mut v = [5, 4, 1, 3, 2];
    v.sort_by(|a, b| a.cmp(b));
    assert!(v == [1, 2, 3, 4, 5]);

    // reverse sorting
    v.sort_by(|a, b| b.cmp(a));
    assert!(v == [5, 4, 3, 2, 1]);
}


fn main(){
use std::cmp::Ordering;

#[derive(Debug)]
struct Point {
    x: i64,
    y: i64,
}

fn main() {
    let mut v = vec![
        Point { x: 3, y: 2 },
        Point { x: 90, y: 78 },
        Point { x: 64, y: 32 },
        Point { x: 1, y: -10 },
        Point { x: 10, y: 10000 },
    ];
    v.sort_by(|a, b| {
        if a.x < b.x {
            Ordering::Less
        } else if a.x == b.x {
            Ordering::Equal
        } else {
            Ordering::Greater
        }
    });
    println!("{:?}", v);
}
}

nightly-only

into_raw_parts(self) -> (*mut T, usize, usize)

Возвращает необработанный указатель на базовые данные

method.into_raw_parts


fn main(){
    #![feature(vec_into_raw_parts)]
    let v: Vec = vec![-1, 0, 1];

    let (ptr, len, cap) = v.into_raw_parts();

    let rebuilt = unsafe {
        // Теперь мы можем вносить изменения в компоненты, например 
        // преобразование необработанного указателя в совместимый тип.
        let ptr = ptr as *mut u32;

        Vec::from_raw_parts(ptr, len, cap)
    };
    assert_eq!(rebuilt, [4294967295, 0, 1]);
}
  • as_ptr()
  • as_mut_ptr() Возвращает небезопасный изменяемый указатель на буфер среза.

Вызывающий должен убедиться, что фрагмент переместит указатель, возвращаемый этой функцией, иначе он будет указывать на мусор. Изменение контейнера, на которое ссылается этот срез, может привести к перераспределению его буфера, что также сделает любые указатели на него недействительными.


fn main(){
    let x = &mut [1, 2, 4];
    let x_ptr = x.as_mut_ptr();

    unsafe {
        for i in 0..x.len() {
            *x_ptr.offset(i as isize) += 2;
        }
    }
    assert_eq!(x, &[3, 4, 6]);
}

windows() - Возвращает итератор по всем смежным окнам размера длины. Окна перекрываются. Паника, если размер равен 0.


fn main(){
    let slice = ['r', 'u', 's', 't'];
    let mut iter = slice.windows(2);
    assert_eq!(iter.next().unwrap(), &['r', 'u']);
    assert_eq!(iter.next().unwrap(), &['u', 's']);
    assert_eq!(iter.next().unwrap(), &['s', 't']);
    assert!(iter.next().is_none());
}

partition_point() - Возвращает индекс точки раздела в соответствии с заданным предикатом


fn main(){
    let v = [1, 2, 3, 3, 5, 6, 7];
    let i = v.partition_point(|&x| x < 5);

    assert_eq!(i, 4);
    assert!(v[..i].iter().all(|&x| x < 5));
    assert!(v[i..].iter().all(|&x| !(x < 5)));
}

chunks(2) - Возвращает итератор по не смежным элементам разделенных по частям


fn main(){
    let content:&str = "abcabcabc";
    let v: Vec<&str>   = content.split("").filter(|s|s.len()>0).collect();
    let chunks = v[..].chunks(3);
    for e in chunks{
      println!("{:?}",e);
    }
/*
    ["a", "b", "c"]
    ["a", "b", "c"]
    ["a", "b", "c"]
*/
}


fn main(){
    let slice = ['l', 'o', 'r', 'e', 'm'];
    let mut iter = slice.chunks(2);
    assert_eq!(iter.next().unwrap(), &['l', 'o']);
    assert_eq!(iter.next().unwrap(), &['r', 'e']);
    assert_eq!(iter.next().unwrap(), &['m']);
    assert!(iter.next().is_none());
}
  • chunks_mut(2) - Возвращает изменяемый итератор по не смежным элементам разделенных по частям

  • chunks_exact() - как chunks, но отсекает не попавшие в чанки элементы

  • chunks_exact_mut()


fn main(){
    let v = &mut [0, 0, 0, 0, 0];
    let mut count = 1;

    for chunk in v.chunks_mut(2) {
        for elem in chunk.iter_mut() {
            *elem += count;
        }
        count += 1;
    }
    assert_eq!(v, &[1, 1, 2, 2, 3]);
}
  • rchunks - Возвращает итератор по chunk_size элементам среза за раз, начиная с конца среза.
  • rchunks_mut
  • rchunks_exact - так же но может усечь начальные элементы если не попали в chank
  • rchunks_exact_mut

fn main(){
    let slice = ['l', 'o', 'r', 'e', 'm'];
    let mut iter = slice.rchunks(2);
    assert_eq!(iter.next().unwrap(), &['e', 'm']);
    assert_eq!(iter.next().unwrap(), &['o', 'r']);
    assert_eq!(iter.next().unwrap(), &['l']);
    assert!(iter.next().is_none());
}
  • split_first()
  • split_first_mut() - Возвращает первый и все остальные элементы среза или None, если он пуст.

fn main(){
    let mut x = &mut [0, 1, 2];

    if let Some((first, elements)) = x.split_first_mut() {
        *first = 3;
        elements[0] = 4;
        elements[1] = 5;
    }
    assert_eq!(x, &[3, 4, 5]);
}
  • split_last()
  • split_last_mut() - Возвращает последний и все остальные элементы среза или None, если он пуст

fn main(){
    let x = &mut [0, 1, 2];

    if let Some((last, elements)) = x.split_last_mut() {
        *last = 3;
        elements[0] = 4;
        elements[1] = 5;
    }
    assert_eq!(x, &[4, 5, 3]);
}

split_at(), split_at_mut() - Разделяет один срез на два по индексу разделителя.

Первый будет содержать все индексы из [0, mid) (за исключением самого индекса), а второй будет содержать все индексы из [mid, len) (исключая сам индекс len).


fn main(){
    let mut v = [1, 0, 3, 0, 5, 6];
    // scoped to restrict the lifetime of the borrows
    {
        let (left, right) = v.split_at_mut(2);
        assert!(left == [1, 0]);
        assert!(right == [3, 0, 5, 6]);
        left[1] = 2;
        right[1] = 4;
    }
    assert!(v == [1, 2, 3, 4, 5, 6]);
}

split(), split_mut() - Возвращает итератор над сегментами, разделенными элементами, которые соответствуют pred. Соответствующий элемент не содержится в подклассах


fn main(){
    let mut v = [10, 40, 30, 20, 60, 50];
    for group in v.split_mut(|num| *num % 3 == 0) {
        group[0] = 1;
    }
    assert_eq!(v, [1, 40, 30, 1, 60, 1]);
}

rsplit(), rsplit_mut() - Возвращает итератор над сегментами, разделенными элементами, которые соответствуют pred, начиная с конца среза и работая назад. Соответствующий элемент не содержится в подклассах.


fn main(){
    let mut v = [100, 400, 300, 200, 600, 500];
    let mut count = 0;
    for group in v.rsplit_mut(|num| *num % 3 == 0) {
        count += 1;
        group[0] = count;
    }
    assert_eq!(v, [3, 400, 300, 2, 600, 1]);
}

splitn(), splitn_mut() Возвращает итератор над сегментами, разделенными элементами, которые соответствуют pred, ограниченным возвратом не более n элементов. Соответствующий элемент не содержится в подклассах.

Последний возвращаемый элемент, если он есть, будет содержать оставшуюся часть среза.

С конца rsplitn(), splitn_mut()


fn main(){
    let mut v = [10, 40, 30, 20, 60, 50];
    for group in v.splitn_mut(2, |num| *num % 3 == 0) {
        group[0] = 1;
    }
    assert_eq!(v, [1, 40, 30, 1, 60, 50]);
}
  • split_inclusive - Итератор по фрагментам, разделенным соответствующими элементами pred
  • split_inclusive_mut

fn main(){
    let slice = [10, 40, 33, 20];
    let mut iter = slice.split_inclusive(|num| num % 3 == 0);

    assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
    assert_eq!(iter.next().unwrap(), &[20]);
    assert!(iter.next().is_none());
}

nightly-only

array_windows - Возвращает итератор по перекрывающимся окнам N элементов среза


fn main(){
    #![feature(array_windows)]
 
    let points: Vec = vec![1,2,3,4,5,6,7];
    let mut differences = Vec::new();
    
    for [previous, current] in points.array_windows().copied() {
    #![feature(array_windows)]differences.push(current - previous);
    }
    println!("{:?}",differences);// [1, 1, 1, 1, 1, 1]
}


fn main(){
    let differences: Vec<_> = points
      .array_windows()
      .copied()
      .map(|[previous, current]| current - previous)
      .collect();
}

Пример реализации Stack через массив

Реализация Stack заданного размера через Vec<T> имеет ненужную избыточность. Нет смысла использовать Vec<T> с переменной длинной, который, к тому же, располагает значения на куче. Используйте массив [T;N] фиксированной длины. Это же позволит располагать Stack и на стеке.


#![allow(dead_code)]

use interior_mutability::Stack;
use std::clone::Clone;
use std::io::{Error, ErrorKind};
use std::result::Result;

mod interior_mutability{
    use super::*;
    const  N: usize = 5;
    #[derive(Debug)]
    pub struct Stack {
        maxsize: usize,
        top: usize,
        pub items: [T;N]
    }

    impl Stack {
        pub fn new(value: T) -> Self
            where
                T: Clone+Copy
        {
            Stack {
                items: [value;N],
                top: 0usize,
                maxsize: N,
            }
        }

        pub fn push(&mut self, i: T) -> Result {
            if self.top >= self.maxsize  {
                Err(Error::new(ErrorKind::Other, "Full stack"))
            } else {

                self.items[self.top]=i;
                self.top += 1;
                Ok(true)
            }
        }

        pub fn pop(&mut self) -> Result
            where
                T: Clone,
        {
            if self.top == 0 {
                Err(Error::new(ErrorKind::Other, "Empty stack"))
            } else {

                self.top -= 1;
                Ok(self.items[self.top].clone())

            }
        }

        pub fn peek(&self) -> Result
            where
                T: Clone,
        {
            if self.top > 0 {
                Ok(self.items[self.top-1].clone())
            } else {
                Err(Error::new(ErrorKind::Other, "Empty stack"))
            }
        }
    }

    #[cfg(test)]
    pub mod test {
        use super::*;

        #[test]
        fn test() {
            let value_type = 0i32;
            let stack: Stack = >::new(0i32);
            let _stack = std::cell::RefCell::new(stack);

            let stack_clone_1 = &_stack;
            let stack_clone_2 = &_stack;

            // verification empty stack
            let result_pop = stack_clone_1.borrow_mut().pop();

            if let Ok(_) = result_pop {
                assert!(false);
            } else {
                assert!(true);
            }

            // verification full stack
            for _i in value_type as usize..N {
                assert_eq!(true, stack_clone_1.borrow_mut().push(10).unwrap_or(false));
            }

            if let Ok(_) = stack_clone_1.borrow_mut().push(3) {
                assert!(false);
            } else {
                assert!(true);
            }

            // verification last value
            stack_clone_1.borrow_mut().pop();
            if let Ok(_) = stack_clone_1.borrow_mut().push(33) {
                assert!(true);
            } else {
                assert!(false);
            }

            let result_pop = stack_clone_1.borrow_mut().pop();

            if let Ok(result) = result_pop {
                assert_eq!(33, result);
            } else {
                assert!(false);
            }
        }
    }
}

fn main() {
    let stack: Stack = >::new(0i32);
    let _stack = std::cell::RefCell::new(stack);
    let stack_clone_1 = &_stack;
    let stack_clone_2 = &_stack;

    stack_clone_2.borrow_mut().push(1);

    stack_clone_1.borrow_mut().pop();
    stack_clone_1.borrow_mut().push(2);

    println!(
        "{}",
        stack_clone_2.borrow().peek().unwrap_or(0)
    );
    stack_clone_1.borrow_mut().push(2);
     println!("{:?}", stack_clone_2.borrow().items); //pub [2, 2, 0, 0, 0, 0, 0, 0, 0, 0]
    stack_clone_2.borrow_mut().push(3);
    stack_clone_2.borrow_mut().pop();


    let stack: Stack<&str> = >::new("");
    let _stack = std::cell::RefCell::new(stack);

    let stack_clone_1 = &_stack;
    let stack_clone_2 = &_stack;

    stack_clone_2.borrow_mut().push("1").is_ok();

    stack_clone_1.borrow_mut().pop().is_ok();
    stack_clone_1.borrow_mut().push("2").is_ok();

    println!(
        "{}",
        stack_clone_2.borrow().peek().unwrap_or("")
    );
    stack_clone_1.borrow_mut().push("2").is_ok();
    println!("{:?}", stack_clone_2.borrow().items); //pub ["2", "2", "", "", "", "", "", "", "", ""]
    stack_clone_2.borrow_mut().push("3").is_ok();
    stack_clone_2.borrow_mut().pop().is_ok();
}