Degen Code

Degen Code

Rust for Pythonistas

Part II: Data, Behavior, Ownership, Traits & Alloy TickMath

Sep 21, 2025
∙ Paid
Share

Data + Behavior ~= Class

Rust stand apart from object-oriented languages (Java, Python, C++, etc) that use classes to encapsulate data and control behavior.

Both are allowed, but Rust places a clear seam between them.

Instead of classes, Rust allows you to attach a behavior (via the impl keyword) to a data structure. You can think of the combination of data + behavior as a class, but just be aware that there’s no higher-level structure that combines the two. If you want something resembling a class, you must define a data structure and its behavior.

The Rust team provides a nice online interface called Rust Playground which lets you run a lot of Rust code in your browser. It allows you to access the standard library and do limited debugging and testing, but you can’t use third party crates or perform operations like making HTTP requests or accessing external systems.

Using the Playground as a kind of live console, let’s define a simple data structure that holds a String for the name and a 64-bit integer for the value. Then we’ll initialize it and print the values:

pub struct DegenData {
    name: String,
    value: i64,
}

fn main() {
    let s = DegenData{
        name: String::from("blazing-fast"), 
        value: 69420,
    };
    println!("{}", s.name);
    println!("{}", s.value);
}

The output is what you’d expect:

blazing-fast
69420

Now convert the standalone prints to two methods that print the values instead:

pub struct DegenData {
    name: String,
    value: i64,
}

impl DegenData {
    fn name(&self) {
        println!("{}", self.name);
    }
    
    fn value(&self) {
        println!("{}", self.value);
    }
}

fn main() {
    let s = DegenData{
        name: String::from("blazing-fast"), 
        value: 69_420,
    };
    s.name();
    s.value();
}

The result is the same:

blazing-fast
69420

Ownership

The &self argument in the name and value methods has a special symbol “&” which signifies that the variable self is a reference to data owned by something else. A reference is stored on the stack and holds a memory address and metadata specific to the type. This is the same concept as a C / C++ pointer, and you’ll often see references called pointers.

Like Python, calling object.method() implicitly provides the self argument to the method. But if you’re coming from Python, you’d likely write a method with a self argument, ignorant of the ownership implications.

Let’s define it in Python style (omitting the &) and see what happens:

[...]

impl DegenData {
    fn name(self) {
        println!("{}", self.name);
    }
    
    fn value(self) {
        println!("{}", self.value);
    }
}

[...]

Attempting to run results in a compiler error:

Compiling playground v0.0.1 (/playground)
error[E0382]: use of moved value: `s`
  --> src/main.rs:22:5
   |
17 |     let s = DegenData{
   |         - move occurs because `s` has type `DegenData`, 
               which does not implement the `Copy` trait
...
21 |     s.name();
   |       ------ `s` moved due to this method call
22 |     s.value();
   |     ^ value used here after move
   |
note: `DegenData::name` takes ownership of the receiver `self`, which moves `s`
  --> src/main.rs:7:13
   |
7  |     fn name(self) {
   |             ^^^^

For more information about this error, try `rustc --explain E0382`.
error: could not compile `playground` (bin "playground") due to 1 previous error

This is a helpful message that illustrates the problem. Since both methods take self, when we call s.name(), the ownership of the DegenData instance passes from s to the name method, where it is bound to the self variable.

This is fine by itself. But we run into trouble when calling s.value() on the next line. It fails because the link between s and the instance of DegenData has been severed. I’m unfamiliar wit hthe compilar implementation, but I assume that s becomes a dangling pointer until it goes out of scope, which is why using it is forbidden.

Let’s comment that line out:

fn main() {
    let s = DegenData{
        name: String::from("blazing-fast"), 
        value: 69_420,
    };
    s.name();
    // s.value();
}

Running it now works as expected:

blazing-fast

So remember that if you need to read data bound to some variable multiple times, you should reach for the reference.

Move vs. Copy

The error above illustrates Rust’s concept of “move semantics”, which signifies the transfer of ownership between variables. User-defined structs are typically pointers that are allocated on the stack — they point to heap-allocated memory, which is given to the Rust runtime by the operating system. Since each allocation involves a system call, it is more expensive than stack allocation.

It’s cheap to reassign ownership of a pointer (which lives on the stack), so move is the default choice for these types.

Contrast that with “copy semantics”, which performs a duplication of the value and assigns that copy to the new variable without performing any ownership transfer.

Python behaves in a similar way. Simple data types like integers and floats are given to functions as a copy of the value. More complex data types like lists, strings, and instances of classes are passed by reference. A key difference is that Python places no restriction on the mutability of these references — they are all mutable, and you can make any number of them.

Many of Rust’s data types are allocated on the stack, and are automatically implemented with copy behavior.

Another related Rust trait is “clone”, which allows you to make an explicit copy of an object instead of jumping through hoops to conform to automatic copy semantics.

Traits

A trait is an abstraction of behavior. A trait can directly define required functions to be implemented on a data structure, or indirectly as a bundle of other traits.

This post is for paid subscribers

Already a paid subscriber? Sign in
© 2025 BowTiedDevil
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture