Rust lang series episode #25 — pointers (#rust-series)

in rust-series •  2 years ago

Good morning everyone, there is a new Rust lang episode. We will talk about pointers in Rust, how to handle them and few things around.

Content

  • Pointers
  • Stack and heap
  • Box
  • References
  • Raw pointers
  • Summary

Pointers

Pointer in programming jargon means something that points to certain place in memory. In especially low level programming languages we can create, get and work with pointers. As you can imagine it uncontrolled pointer is a strong "weapon" which can lead to many undesirable issues. That's why raw pointer in Rust it's not used as a primary feature and we rather using references if needed which has lot of guarantees but are on the other hand more restricted.

Now it should be mentioned that although technically there is just one physical memory (although there can be multiple modules) there are two major memory areas from application programming point of view. Those are stack and heap. Stack is place where function calls are stored, parameters and static variables are kept here whereas heap is a place for dynamic content in general.

Variables on stack

So far we've mostly created variables that live on stack as it's memory for static variables. There are some advantages but not always possible to use just stack especially when you need to work with dynamic content.

let on_stack = 1;

Variables on heap

When dealing with data types that can change their size or are created during runtime we need to use heap. In Rust we can use Box to allocate heap in safe way. Heap is therefore part of memory for dynamic allocation.

let on_heap = Box::new(1);

But don't be tricked, even if we define vector on stack its data are always on heap because it has dynamic content.

let on_stack_and_help = vec![1,2,3];

Create new boxed value

Now we show Box type which is major weapon for heap allocation.
Box<T> is an owned pointer or simply "a box".

let boxed_integer = Box::new(5);
let boxed_vector = Box::new(vec![1,2,3]);
let boxed_str = Box::new("Boxed Steemit string");

box keyword

If you prefer to use nightly Rust version with latest language features, you can also use box keyword to create boxed variables.

#![feature(box_syntax)]

fn main() {
    let boxed_integer = box 5;
    let boxed_vector = box vec![1,2,3];
    let boxed_str = box "Boxed Steemit string";

    println!("boxed_integer: {}", boxed_integer);
    println!("boxed_vector: {:?}", boxed_vector);
    println!("boxed_str: {}", boxed_str);
}

# output
boxed_integer: 5
boxed_vector: [1, 2, 3]
boxed_str: Boxed Steemit string

Note that you can switch to nightly Rust version by using

rustup default nightly

and back to stable like this

rustup default stable

Automatic Box dereferencing

Notice that when Rust can provide auto dereference. It also works with Box in certain cases because we can imagine Box as safe reference and rust knows how to dereference it in cases like this. Therefore this will work

let boxed_str = Box::new("Boxed Steemit string");
println!("{}", boxed_str);

# output
Boxed Steemit string

And it's the same as this

let boxed_str = Box::new("Boxed Steemit string");
println!("{}", *boxed_str);

# output
Boxed Steemit string

Dereferencing boxes

If Rust compiler cannot dereference automatically, it's required to dereference manually with *. My advice is to alway dereference explicitly, it makes code obvious for a reader or maintainer. Check this piece of code.

let a = Box::new(5);
let b = 5;
let c  = *a + b;
println!("c : {}", c);

# output
c : 10

References

Speaking about pointers and related things, we already know reference which are either &T or mutable &mut T. References are controlled or guaranteed pointers in Rust. This means they are always valid and should never point to invalid memory position.

let original = 1;
let reference_to_original = &original;
println!("{}", reference_to_original);

# output
1

Raw pointers

There are also C-like raw pointer in rust with no lifetime and ownership in rust. They under lowest level of restrictions and cannot be dereferenced outside unsafe block
*const T and *mut T.

let original = "Steemiters know raw pointers";
let raw_pointer: *const &str = &original;
let points_at = unsafe {*raw_pointer};
println!("{}", points_at);

# output
Steemiters know raw pointers

Typical usage of raw pointers is FFI (Foreign Function Interface) which allows calling C language functions from various libraries which we will explain in the future.

Summary

Variables are created on

  • stack - static
  • heap - dynamic and boxed

Rust provides two major types of pointers with various levels of security

  • safe - references
  • unsafe - raw pointers

Postfix

That's all for now, thank you for your appreciations, feel free to comment and point out possible mistakes (first 24 hours works the best but any time is fine). May Jesus bless your programming skills, use them wisely and see you next time.

Meanwhile you can also check official documentation related to pointers:

#rust-series
#rust-lang
#rust

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!