Marcin Jahn | Dev Notebook
  • Home
  • Programming
  • Technologies
  • Projects
  • About
  • Home
  • Programming
  • Technologies
  • Projects
  • About
  • An icon of the Core section Core
    • Programs Execution
    • Stack and Heap
    • Asynchronous Programming
      • Overview
      • Event Queues
      • Fibers
      • Stackless Coroutines
  • An icon of the .NET section .NET
    • HTTPClient
    • Async
      • How Async Works
      • TAP Tips
    • Equality
    • Comparisons
    • Enumerables
    • Unit Tests
    • Generic Host
    • Logging
    • Configuration
    • Records
    • Nullability
    • Garbage Collector
    • IL and Allocations
    • gRPC
    • Source Generators
    • Platform Invoke
    • ASP.NET Core
      • Overview
      • Middleware
      • Razor Pages
      • Routing in Razor Pages
      • Web APIs
      • Filters
      • Identity
      • Validation
      • Tips
    • Entity Framework Core
      • Overview
      • Testing
      • Tips
  • An icon of the Angular section Angular
    • Overview
    • Components
    • Directives
    • Services and DI
    • Routing
    • Observables (RxJS)
    • Forms
    • Pipes
    • HTTP
    • Modules
    • NgRx
    • Angular Universal
    • Tips
    • Standalone Components
  • An icon of the JavaScript section JavaScript
    • OOP
    • JavaScript - The Weird Parts
    • JS Functions
    • ES Modules
    • Node.js
    • Axios Tips
    • TypeScript
      • TypeScript Environment Setup
      • TypeScript Tips
    • React
      • React Routing
      • MobX
    • Advanced Vue.js Features
  • An icon of the Rust section Rust
    • Overview
    • Cargo
    • Basics
    • Ownership
    • Structures
    • Enums
    • Organization
    • Collections
    • Error Handling
    • Generics
    • Traits
    • Lifetimes
    • Closures
    • Raw Pointers
    • Smart Pointers
    • Concurrency
    • Testing
    • Tips
  • An icon of the C/C++ section C/C++
    • Compilation
    • Structures
    • OOP in C
    • Pointers
    • Strings
    • Dynamic Memory
    • argc and argv Visualization
  • An icon of the GTK section GTK
    • Overview
    • GObject
    • GJS
  • An icon of the CSS section CSS
    • Responsive Design
    • CSS Tips
    • CSS Pixel
  • An icon of the Unity section Unity
    • Unity
  • An icon of the Functional Programming section Functional Programming
    • Fundamentals of Functional Programming
    • .NET Functional Features
    • Signatures
    • Function Composition
    • Error Handling
    • Partial Application
    • Modularity
    • Category Theory
      • Overview
      • Monoid
      • Other Magmas
      • Functors
  • An icon of the Algorithms section Algorithms
    • Big O Notation
    • Array
    • Linked List
    • Queue
    • Hash Table and Set
    • Tree
    • Sorting
    • Searching
  • An icon of the Architecture section Architecture
    • What is architecture?
    • Domain-Driven Design
    • ASP.NET Core Projects
  • An icon of the Core section Core
    • Programs Execution
    • Stack and Heap
    • Asynchronous Programming
      • Overview
      • Event Queues
      • Fibers
      • Stackless Coroutines
  • An icon of the .NET section .NET
    • HTTPClient
    • Async
      • How Async Works
      • TAP Tips
    • Equality
    • Comparisons
    • Enumerables
    • Unit Tests
    • Generic Host
    • Logging
    • Configuration
    • Records
    • Nullability
    • Garbage Collector
    • IL and Allocations
    • gRPC
    • Source Generators
    • Platform Invoke
    • ASP.NET Core
      • Overview
      • Middleware
      • Razor Pages
      • Routing in Razor Pages
      • Web APIs
      • Filters
      • Identity
      • Validation
      • Tips
    • Entity Framework Core
      • Overview
      • Testing
      • Tips
  • An icon of the Angular section Angular
    • Overview
    • Components
    • Directives
    • Services and DI
    • Routing
    • Observables (RxJS)
    • Forms
    • Pipes
    • HTTP
    • Modules
    • NgRx
    • Angular Universal
    • Tips
    • Standalone Components
  • An icon of the JavaScript section JavaScript
    • OOP
    • JavaScript - The Weird Parts
    • JS Functions
    • ES Modules
    • Node.js
    • Axios Tips
    • TypeScript
      • TypeScript Environment Setup
      • TypeScript Tips
    • React
      • React Routing
      • MobX
    • Advanced Vue.js Features
  • An icon of the Rust section Rust
    • Overview
    • Cargo
    • Basics
    • Ownership
    • Structures
    • Enums
    • Organization
    • Collections
    • Error Handling
    • Generics
    • Traits
    • Lifetimes
    • Closures
    • Raw Pointers
    • Smart Pointers
    • Concurrency
    • Testing
    • Tips
  • An icon of the C/C++ section C/C++
    • Compilation
    • Structures
    • OOP in C
    • Pointers
    • Strings
    • Dynamic Memory
    • argc and argv Visualization
  • An icon of the GTK section GTK
    • Overview
    • GObject
    • GJS
  • An icon of the CSS section CSS
    • Responsive Design
    • CSS Tips
    • CSS Pixel
  • An icon of the Unity section Unity
    • Unity
  • An icon of the Functional Programming section Functional Programming
    • Fundamentals of Functional Programming
    • .NET Functional Features
    • Signatures
    • Function Composition
    • Error Handling
    • Partial Application
    • Modularity
    • Category Theory
      • Overview
      • Monoid
      • Other Magmas
      • Functors
  • An icon of the Algorithms section Algorithms
    • Big O Notation
    • Array
    • Linked List
    • Queue
    • Hash Table and Set
    • Tree
    • Sorting
    • Searching
  • An icon of the Architecture section Architecture
    • What is architecture?
    • Domain-Driven Design
    • ASP.NET Core Projects

Collections

Arrays

Arrays are placed on the stack, since their size is static and always needs to be predefined.

let countries = ["Poland", "Brazil"];

Iterator is returned with countries.iter();.

for country in countries.iter() {
}

Array is typed like this: [u32, 5] - 5 elements of type u32. Each array with different type and size is like a separate type in Rust.

Vectors

Another collection type. It’s dynamic, so it’s placed on the heap (it’s a struct). Vec<T> is like a List<T> in C#. They are more expensive than arrays. Elements are placed next to each other in memory.

Creating vectors:

let v: Vec<i32> = Vec::new(); //empty
let v = vec![1, 2, 3]; // infers type, uses a macro

Operations on vectors:

let mut v = Vec::new(); // no type needed, it's infered from the code below
// update
v.push(5);
v.push(6);
v.push(7);
// read
let third: &i32 = &v[2];
match v.get(2) {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
} // returns Option<&T>

The second way of reading will not panic if we try to access element out of index. It will return Option.None instead.

HashMaps

use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
let team_name = String::from("Blue");
let score = scores.get(&team_name); // returns Option<&T>
scores.entry(String::from("Yellow")).or_insert(60); // inserts only if Yellow key is not there yet

Iterators

Iterators give access to consecutive elements in collections. Iterators implement the Iterator trait, which exposes next() method and Item. It’s easy to define our own iterators. Iterators provide zero-cost abstractions, they are very performant.

There are three methods on collections that return iterators:

  • iter() - iterates over immutable references to items in the collection
  • iter_mut() - iterates over mutable references to items in the collection
  • into_iter() - returns owned values from the collection

Consuming Adaptors

Some methods defined on the Iterator trait take ownership of the iterator and return something useful. An example is the sum() method.

Collect Function

The collect() function consumes iterator into an actual collection of values.

let args: Vec<String> = env::args().collect();

It also has a specific implementation that can turn an Iterator<Result<T>> into a Result<Vec<T>> (so it kind of reverses the outer layers).

collect is one of cases where we often need to provide the expected output type in cases where various outputs are possible.

When using the ? operator, it is not a part of expected type. E.g.:

let table_names = table_cells
.iter()
.map(|table_cell| table_cell.get_table_name())
.collect::<Result<Vec<String>>>()?;

I have to provide type information to collect, ? alone is not enough to infer the type. Also, I cannot just do:

let table_names: Vec<String> = table_cells
.iter()
.map(|table_cell| table_cell.get_table_name())
.collect()?;

The compiler only looks at the result of collect and not ?, so the specified type of <Vec<String>> is wrong, because the compiler knows that table_cell.get_table_name() returns a Result<String>.

Iterator Adaptors

Some other methods can transform an iterator into another kind of iterator. These iterators are lazy, so to actually do anything the resulting iterator needs to be consumed.

Examples:

  • map() - takes a closure to be executed agains each item and returns closure’s result. It’s similar to JS’s map in concept.
  • filter() - returns an iterator that filters source collection based on a closure returning bool.
  • skip() - skips some items.

collect() applied on top of iterator adaptor returns a new collection of values.

←  Organization
Error Handling  →
© 2023 Marcin Jahn | Dev Notebook | All Rights Reserved. | Built with Astro.