Traits
- Definition: Traits are a way to define shared behavior in Rust. They define a set of methods that a type must implement in order to fulfill the contract of the trait.
- Purpose: Traits are used for abstracting over types, allowing you to write generic code that can work with multiple types as long as they implement the required behavior specified by the trait.
- Syntax: Traits are declared using the
trait
keyword, followed by the trait’s name and a set of method signatures. Types can then implement traits using theimpl
keyword.
<span class="line"><span style="color: #D8DEE9">trait</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">Drawable</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">fn</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">draw</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&</span><span style="color: #D8DEE9">self</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">Circle</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF"> radius</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">f64</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">impl</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">Drawable</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">Circle</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">fn</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">draw</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&</span><span style="color: #D8DEE9">self</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">println</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">Drawing a circle with radius {}</span><span style="color: #ECEFF4">"</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">radius</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
Closures
- Definition: Closures are anonymous functions that can capture variables from their surrounding environment. They are similar to functions but are defined inline using a concise syntax.
- Purpose: Closures are useful for writing code that requires a small, one-off function without the need to define a separate named function. They are often used for passing behavior as arguments to higher-order functions.
- Syntax: Closures are written using a pipe (
|
) syntax to specify the parameters, followed by the body of the closure. They can capture variables from their enclosing scope using a move or borrow semantics.
<span class="line"><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">add</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9">x</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">y</span><span style="color: #D8DEE9FF">| x + y</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #88C0D0">println</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">The sum is: {}</span><span style="color: #ECEFF4">"</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">add</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">3</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
where clause
In Rust, the where
clause is used in function declarations, trait declarations, and various other contexts to specify additional requirements or bounds on the generic parameters or associated types.
When used in a function declaration, the where
clause typically follows the list of generic parameters and is used to specify trait bounds or additional constraints on those parameters.
<span class="line"><span style="color: #D8DEE9">fn</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">squares</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> Vec</span><span style="color: #ECEFF4"><</span><span style="color: #D8DEE9FF">i32</span><span style="color: #ECEFF4">></span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #B48EAD">1..5</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">map</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9">x</span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">x</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">x</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">collect</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">println</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">{:?}</span><span style="color: #ECEFF4">"</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">squares</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// This will print [1, 4, 9, 16]</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
- Range Creation:
let range = 1..5;
- Mapping Function:
let squares = range.map(|x| x * x);
- The
map
method takes a closure|x| x * x
which squares each elementx
in the range.
- The
- Collecting Results:
let squares: Vec<i32> = squares.collect();
- The
collect
method is used to consume the iterator and collect the results into a vector.
- The
- This creates a range from 1 to 4.
core::array::from_fn
The core::array::from_fn
function in Rust is a utility that allows you to generate an array of fixed size by applying a closure to each index.
<span class="line"><span style="color: #D8DEE9">use</span><span style="color: #D8DEE9FF"> core</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF">:</span><span style="color: #D8DEE9">array</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">fn</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4"> </span><span style="color: #616E88">// Create an array of 10 elements where each element is its index squared</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">squares</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> [usize; </span><span style="color: #B48EAD">10</span><span style="color: #D8DEE9FF">] </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">array</span><span style="color: #D8DEE9FF">::</span><span style="color: #88C0D0">from_fn</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">println</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">{:?}</span><span style="color: #ECEFF4">"</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">squares</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Prints: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
Option<T>
Option<T>
is an enum in Rust that represents an optional value. It can be either:
Some(T)
: Indicates that there is a value of typeT
.None
: Indicates that there is no value.
The Option
type is used extensively in Rust to handle cases where a value might be absent
if let
In Rust, the if let
construct is used to match a pattern and execute code if the match is successful. It can be used to handle Option
and Result
types more ergonomically. Specifically, if let Some(next) = inputs_iter.peek()
checks if peek()
returns Some
and extracts the value into next
. If peek()
returns None
, the else
block is executed.
<span class="line"><span style="color: #D8DEE9">fn</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4"> </span><span style="color: #616E88">// Define a vector of vectors</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">inputs</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">vec</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">[</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">vec</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #D8DEE9FF">]</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">vec</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">6</span><span style="color: #D8DEE9FF">]</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">vec</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">7</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">8</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">9</span><span style="color: #D8DEE9FF">]</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF"> ]</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4"> </span><span style="color: #616E88">// Convert the vector into an iterator and make it peekable</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mut</span><span style="color: #D8DEE9FF"> inputs_iter </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">inputs</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">into_iter</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">peekable</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4"> </span><span style="color: #616E88">// Loop through the iterator</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">while</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">Some</span><span style="color: #D8DEE9FF">(current) </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">inputs_iter</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">next</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4"> </span><span style="color: #616E88">// Print the current element</span></span>
<span class="line"><span style="color: #D8DEE9FF"> println!(</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">Current: {:?}</span><span style="color: #ECEFF4">"</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> current);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4"> </span><span style="color: #616E88">// Peek at the next element</span></span>
<span class="line"><span style="color: #D8DEE9FF"> if let </span><span style="color: #88C0D0">Some</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">next</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> = inputs_iter.</span><span style="color: #88C0D0">peek</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4"> </span><span style="color: #616E88">// If there is a next element, print it</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">println</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">Next: {:?}</span><span style="color: #ECEFF4">"</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">next</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> else </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4"> </span><span style="color: #616E88">// If there are no more elements, print a message</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">println</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">No more elements.</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
Ownership & borrowing
In Rust, “ownership” refers to the ownership system that Rust uses to manage memory safely without a garbage collector. Ownership is a set of rules that governs how memory is managed, ensuring that memory is freed when it is no longer needed.
When we say that a function or method takes ownership of data, it means that the function or method takes control over the data, and the original owner can no longer access the data. Conversely, when we say that a function or method borrows data, it means that the function or method can temporarily use the data, but the original owner retains control and can continue to use it once the borrowing ends.
ownership:
<span class="line"><span style="color: #D8DEE9">fn</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">borrow</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">v</span><span style="color: #D8DEE9FF">: </span><span style="color: #81A1C1">&</span><span style="color: #D8DEE9">Vec</span><span style="color: #81A1C1"><</span><span style="color: #D8DEE9">i32</span><span style="color: #81A1C1">></span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4"> </span><span style="color: #616E88">// `v` is borrowed here, not owned</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">println</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">{:?}</span><span style="color: #ECEFF4">"</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">v</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">fn</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">let</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">v</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">vec</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #D8DEE9FF">]</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">borrow</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&</span><span style="color: #D8DEE9">v</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4"> </span><span style="color: #616E88">// v is still accessible here because its ownership was not transferred</span></span>
<span class="line"><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">println</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">{:?}</span><span style="color: #ECEFF4">"</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">v</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// This is fine</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
Immutable borrowing
When you borrow a value immutably, you use &
. This means that the function can read the value but cannot modify it
mutable borrowing
When you borrow a value mutably, you use &mut
. This allows the function to modify the value