Lesson 1

Ownership and moves

Understand what happens when you assign, pass, or return values in Rust.

Level
Beginner
Duration
25 min
Updated

Why ownership exists

A String allocates a buffer on the heap. That buffer must be released exactly once: failing to release it wastes memory; releasing it twice or too early can make the program access memory that is no longer valid.

Rust prevents that problem without a garbage collector and without requiring manual calls to free. Every value has a single owner and, when that owner goes out of scope, Rust runs drop and releases its associated resources.

That is why let s2 = s1; does not duplicate a String buffer: it transfers ownership to s2 and invalidates s1. This is a move. Copy types are duplicated implicitly; clone creates an explicit duplicate, while a reference lets code use the value temporarily without becoming its owner.

Memory state

  • STACK · s1owner · stack struct
  • ptr0x1
  • len4
  • cap4
  • HEAP · 0x1h · o · l · a
01 / 06ONE OWNER

What changes compared with other languages

The same assignment does not express the same operation in every language. If a provides access to a value backed by dynamically allocated memory, the usual behavior is:

Language When b = a runs Releasing the resource
TypeScript / Java A managed reference is copied. Both a and b provide access to the same object. The garbage collector acts after the object becomes unreachable.
C++ A type such as std::string is copied. A move may be enabled with b = std::move(a); afterwards, a remains valid but its state may have changed. Each object releases its resources from its destructor through RAII; direct use of delete is normally unnecessary.
Rust A type such as String is moved: b receives the value and a can no longer be used. Duplicating the buffer requires an explicit a.clone(). The resource is released through drop when its current owner leaves scope.

Rust does allow multiple shared references, &T. In safe code, borrowing prevents mutable access from overlapping with any other access to the same value: there may be several shared references or one mutable reference, but not both at the same time. The compiler checks this rule and also ensures that no reference outlives the value it points to.

Exercise 01 · Ownership

Complete two functions without consuming their input values.

Both functions only need to read their arguments. Accept them by reference, complete the code, and run the tests.

0/2correct

Implement saludo_mas_largo to return one of the texts received by reference. Implement crear_saludo to create a new String without consuming the input argument.

01

Implement

Complete one function in each editor.

Function 01

Select the longest text

Unchanged

Accept two &str values and return the longest one.

/// Devuelve el saludo más largo sin tomar la propiedad.
pub fn saludo_mas_largo(a: String, b: String) -> String {
    todo!("devuelve a o b")
}

Function 02

Build a new String

Unchanged

Accept an &str and create a greeting without consuming the input value.

/// Construye un saludo nuevo sin consumir el nombre.
pub fn crear_saludo(nombre: String) -> String {
    todo!("construye un String nuevo")
}
02

Check

Run the tests and correct the code using the Rust diagnostic.

returns the longest textthe name remains available
Compiler

Modify the code before running the tests.

03

Help

View a hint or compare your implementation with the solution.

Run an attempt to unlock the solution.

Summary

  • Every value has a single owner; when it leaves scope, the value is freed automatically.
  • Assigning or passing a value with heap data moves ownership; the previous variable becomes invalid.
  • clone() creates an explicit deep copy when you truly need two owners.
  • Copy types (no heap) are copied on assignment and both variables stay alive.
  • The compiler turns memory errors into compile errors with actionable messages.

Sources