惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Scott Helme
Scott Helme
N
Netflix TechBlog - Medium
AI
AI
Security Latest
Security Latest
GbyAI
GbyAI
P
Proofpoint News Feed
Y
Y Combinator Blog
A
Arctic Wolf
G
Google Developers Blog
U
Unit 42
爱范儿
爱范儿
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
Vulnerabilities – Threatpost
Know Your Adversary
Know Your Adversary
Cisco Talos Blog
Cisco Talos Blog
T
Tor Project blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threatpost
L
Lohrmann on Cybersecurity
C
CERT Recently Published Vulnerability Notes
C
Check Point Blog
B
Blog RSS Feed
The GitHub Blog
The GitHub Blog
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 【当耐特】
博客园 - Franky
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
C
Cisco Blogs
云风的 BLOG
云风的 BLOG
NISL@THU
NISL@THU
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Microsoft Security Blog
Microsoft Security Blog
T
The Blog of Author Tim Ferriss
阮一峰的网络日志
阮一峰的网络日志
Latest news
Latest news
L
LINUX DO - 最新话题
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
WordPress大学
WordPress大学
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
酷 壳 – CoolShell
酷 壳 – CoolShell
大猫的无限游戏
大猫的无限游戏
The Hacker News
The Hacker News
Simon Willison's Weblog
Simon Willison's Weblog
V
V2EX
Project Zero
Project Zero
博客园_首页

Stonecharioteer on Tech

I Traced My Traffic Through a Home Tailscale Exit Node What Was I Reading Last? In Three Not-So-Easy Pieces Dogfooding Is Hard Code blocks in your books, finally GoForGo v0.9.0 Merrilin - We built an app to read books I use a Macbook now Data Structures & Algorithms - Preparing for Interviews Using a local DNS namespace for local service discovery Direction KOllector - Publishing KOReader Highlights gbt: branches touched in the last 24 hours A Soiree into Symbols in Ruby Some Smalltalk about Ruby Loops Ruby Blocks Returning from Ruby Blocks, Procs and Lambdas My Linux Laptop Finally Works: How Claude Helped Me Fix Years of Annoyances TIL: Watchexec - Modern File Watching for Development Workflows A Less Busy Mind GoForGo - Learn Go through live examples Migrating My Old Blog to Hugo with Claude The Qtile Window Manager: A Python-Powered Tiling Experience Read the RFCs that Built the Internet Py-x-Protobuf - Or How I Learned to Stop Worrying and Love Protocol Buffers Python Reverse a List New Beginnings Leaving ChainSafe Systems Screen Lock for Cinnamon Desktop using Zenity and Terminal Commands Crews Not Teams A System for Getting Better at LeetCode So Far So Rust Retrying HTTP Requests with Rust A Primer on Control Charts Learning Rust Using Custom Delimiters in Jinja Templates TIL: Creating Fixed Length Iterables in Python Documentation Without Assumption Vagrant Python - A Reflection in 2022 Learning Golang No, A Virtual Machine Is Not Enough: Why Developers Need Native Linux Empathy in Tech For Those Who Came in Late A Weekend With PostgreSQL TIL: Gooey and Python Fire for Quick GUIs and CLIs TIL: 2ality - Dr. Axel Rauschmayer's JavaScript Blog TIL: MassDNS - High-Performance Bulk DNS Lookups TIL: Matomo Analytics, Google Tech Writing, Memory Programming, and NES TV Signals TIL: MontyDB - MongoDB Implemented in Python Returning to the Craft of Programming TIL: CPUFetch, OneFetch, and Learn CSS TIL: DNS Performance Testing and Pi-hole with Unbound TIL: Eli Bendersky's Blog, Awesome By Example, NoCoDB, and Martin Kleppmann TIL: CRDTs, Extreme HTTP Performance, and BYTEPATH Game TIL: AutoInvent, ASGI, Python Packaging, RAPIDS GPU Computing, and FlaskCon TIL: MangaDesk - Terminal Client for MangaDex TIL: McFly - Smart Shell History Search TIL: Siege Load Testing and Awesome FastAPI Resources TIL: Ventoy Bootable USB and Justniffer Network Analysis TIL: CLI Code Review, Git Split Diffs, and Internal Combustion Engine TIL: Benford's Law, Web Security Headers, Event Sourcing, and Mozilla Security Guidelines How to Write Documentation - The README.md File The Importance of Documentation TIL: NNgroup UX Research, SponsorBlock, and Labella Python Library TIL: The Little Book of Rust Macros and Rust Performance Book TIL: Git-Bug Distributed Issue Tracker and Omni Kubernetes Monitoring TIL: Zellij - Modern Terminal Multiplexer TIL: How Discord Handles 2.5 Million Concurrent Voice Users TIL: Volumio - The Audiophile Music Player TIL: Areopagitica - Milton's Defense of Free Speech TIL: Fast Node Manager, Zoxide Smart CD, Technical Writing, PyO3, and Qubes OS TIL: Slurm Workload Manager for HPC Clusters TIL: Data Visualization Guide and Oso Authorization Academy TIL: CORS Deep Dive, Piku Tiny PaaS, Rust Strings, and Deno Standard Library TIL: Raspberry Pi OS Development, Vim Beginner Guide, Password Management, and QueryBook TIL: uBlock Origin Performance Optimization on Firefox TIL: Breaking PostgreSQL at Scale and LeetCode Problem Patterns TIL: Awesome Tmux Resources for Terminal Multiplexing TIL: Grit - A Multitree-Based Personal Task Manager TIL: Lens 4.2 Kubernetes IDE, Shell Scripting Guide, and Dark HTTP Server Do The Job You Hate So You Won't Hate The Job You Love TIL: Innernet VPN Solution and NoteCalc Calculator App TIL: Argo CD for GitOps and Lens Kubernetes IDE TIL: Modern Rust CLI Tools - System Monitoring, HTTP Requests, and DNS TIL: tz - A Time Zone Helper Tool TIL: Distributed Systems Education, Fallacies, and Self-Hosted Internet Archiving TIL: Real-Time Voice Cloning Technology TIL: ChartMuseum for Helm, AMD's Corporate Journey, and Kubernetes Pod Scaling TIL: Docker and Kubernetes Tools - Whaler, Descheduler, and Dive TIL: Post-Mortem Collection, Terminal Plotting, and Technical Twitter TIL: Dark Mode Toggle Web Component by Google Chrome Labs TIL: Python eval(), exec(), and compile() Functions TIL: Camelot PDF Tables, PostgreSQL Row Level Security, Zerodha Varsity, and Write Yourself a Git TIL: fuser Command for Process and File Investigation TIL: i Hate Regex - The Ultimate Regex Cheat Sheet TIL: Dolt - Git for Data and Database Version Control TIL: x86 Assembly Programming and SafeEyes Break Reminder TIL: Comprehensive Distributed Systems Reading List TIL: Cosmopolitan C Library, Distributed Systems Book, High Performance Browser Networking, and Rust Roguelike Tutorial TIL: ABlog for Sphinx - Documentation as a Blog Platform
Explicit is Better than Implicit: Rust for Pythonistas
2022-03-26 · via Stonecharioteer on Tech
1
2
$ python -m this | sed -n '4p'
Explicit is better than implicit.

About Me

Hi! I’m Vinay Keerthi, I go by @stonecharioteer1 everywhere. I blog at stonecharioteer.com and am self-taught. I have been using Python for 8 years, building web applications (Flask), command line tools (Click), sometimes GUIs (PyQt5/Plotly Dash), and automating pipelines (Airflow, flask-scheduler).

At the time of this talk, I was doing Data Engineering at Merkle Science, a cryptocurrency analytics firm. Previously I worked at Visa, GKN Driveline, and Flipkart. I’d been writing Rust code for ~30 days when I gave this talk. Beware the errors.

What’s with the Title?

The Zen of Python states “Explicit is better than implicit.” Rust embodies this principle to a fault, and is a natural successor to this ideal.

This is not a Rust tutorial

This post covers why you might want to learn Rust as a Python developer, what it looks like, and how to get started. It’s not a comprehensive tutorial.

What This Talk Covers

  • Why Rust?
  • I already know Python - why would I learn Rust?
  • Why not Go/Java/C++?
  • What does Rust look like?
  • How do I learn?
  • Memory management concepts
  • Strings in Rust
  • The module system

Why Rust?

I’ve been writing Python code my entire career and wanted to try something new. I’d tried some Go resources, but kept coming back to Rust. I first heard about Rust on Hacker News.

What did I know going in?

  • Rust is fast
  • Rust has a steep learning curve
  • It’s low level
  • It’s got something called the borrow checker
  • Strings are weird?

But I Already Know Python!

And that’s good. Use what you know for problems you want to solve quickly. Python can do almost anything. If you need to scale, think about distributing your tasks across workers.

  • Use Pandas, NumPy, and other libraries designed for speed over native data types
  • Use Cython or PyCuda to write faster code
  • Try PyPy for JIT - it’s faster

Then Why Would I Learn Rust?

Shipping Python Applications is Getting Harder

There’s a paradox of choice: poetry, pyenv, virtualenvwrapper, flit, conda. There are ways to ship a single binary, but they ship the Python interpreter with them.

Learning Lower-Level Concepts

If you’re self-taught like me, you should learn a lower-level language:

  • Python doesn’t teach you about memory management
  • What are threads, really?
  • How do you implement a truly safe multi-threaded application?
  • How does the memory model work?

Other Benefits

  • Rust gives you simple and safe concurrency
  • It makes you a better programmer (more on this later)

Why Not X?

X is usually Go, Java, C++, or C. Follow your instinct - learn what you want to.

Performance matters, and it should. Ownership and borrowing is interesting. Have you seen really small binaries? Cargo is an amazing package manager that does everything for you.

What Does It Look Like?

Let’s start with the classic hello world:

1
2
3
fn main() {
    println!("ನಮಸ್ಕಾರ, BangPypers!");
}

Here’s some real code - a simple function that calculates sale prices:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// This store is having a sale where if the price is an even number, you get
// 10 Rustbucks off, but if it's an odd number, it's 5 Rustbucks off.

// This is the function that is triggered when you're building a binary, a CLI or a server
// instance for example.
fn main() {
    let original_price = 51;
    println!("Your sale price is {}", sale_price(original_price));
}

// This function takes an i32 integer and returns an i32 integer.
// Rust's typing is extremely strict. If it looks like a duck, don't trust it.
// If you want something that quacks, then don't ask for a duck. Ask for something
// that quacks.
fn sale_price(price: i32) -> i32 {
    if is_even(price) {
        price - 10
    } else {
        price - 5
    }
}

// This function takes an i32 and returns a boolean value.
// Even the number size really matters. Rust showed me that we use inconsistent
// database schemas in some places because I was using u32 (unsigned integer 32 bit),
// and one particular database schema returned a u64 instead. That's an error you wouldn't get
// with Python.
fn is_even(num: i32) -> bool {
    num % 2 == 0
}

Here’s a more complex example showing structs and implementations:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#[derive(Debug)]
struct Package {
    sender_country: String,
    recipient_country: String,
    weight_in_grams: i32,
}

impl Package {
    fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
        if weight_in_grams <= 0 {
            panic!("uh-oh! what do you mean that the weight is negative?");
        } else {
            return Package {
                sender_country,
                recipient_country,
                weight_in_grams,
            };
        }
    }

    fn is_international(&self) -> bool {
        self.sender_country != self.recipient_country
    }

    fn get_fees(&self, cents_per_gram: i32) -> i32 {
        self.weight_in_grams * cents_per_gram
    }
}

Memory Management in Rust: Scope and Mutability

1
2
3
4
5
6
7
8
let x = 10;
{
    let mut x = 15;
    println!("x = {}", x);
    x = 18;
    println!("x = {}", x);
}
println!("x = {}", x)

Variables have scopes, and you must explicitly declare them as mutable with mut.

Memory Management in Rust: Movement

You can’t keep passing variables around and copying them without thinking. Rust’s memory model is centered around Ownership and Borrowing.

1
2
3
4
5
6
7
fn main() {
    let x: String = "hello".to_string();
    println!("x = {}", x);
    let y = x;
    println!("y = {}", y);
    println!("x = {}", x); // ERROR: This won't even compile because x has "moved" into y.
}

The Rust analyzer tells us that we can’t use the value of x because it has moved, and that String doesn’t implement the Copy trait.

Traits

Traits are abilities types and structs can have in Rust. You can implement a trait on any datatype. Some are derivable while others need to be implemented manually. You can override traits to give your datatypes not-so-obvious features.

Think of it like overriding or implementing __dunder__ methods in Python. Note that this is a gross trivialization of what traits are.

Memory Management in Rust: Borrowing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
fn borrow_a_string(x: &str) {
    println!("I've only borrowed a string. The value is {}", x);
}

fn move_a_string(x: String) {
    println!("I've taken ownership of a string. The value is {}", x);
}

fn main() {
    let v = String::from("The cake is a lie!");
    borrow_a_string(&v); // v is still in scope because this is just a borrow.
    move_a_string(v); // v is a move, so it cannot be used after this.
    println!("v={}", v); // if you try this, the compiler will complain.
}

Memory Management in Rust: Mutable Borrowing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fn append_to_a_vector(v: &mut Vec<u32>, a: u32) {
    v.push(a);
}

pub fn run() {
    let mut x = vec![10, 20, 30, 40];
    println!("Initial Vector: {:?}", x);
    append_to_a_vector(&mut x, 10);
    println!("Final Vector: {:?}", x);
}

Strings in Rust

Strings are UTF-8 encoded in Rust, so a string length might not be what you think it is. The docs explain this well. They use the Devanagari script as an example of why this is not straightforward.

For example: ನಮಸ್ಕಾರ would not be just 4 characters.

1
2
3
4
5
pub fn run() {
    let x = "ನಮಸ್ಕಾರ";
    println!("{} = {:?}", x, x.as_bytes());
    println!("{} = {:?}", x, x.chars().collect::<Vec<char>>());
}

Here’s a practical example showing string slices vs owned strings:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
// task is to call one of these two functions on each value depending on what
// you think each value is. That is, add either `string_slice` or `string`
// before the parentheses on each line. If you're right, it will compile!

fn string_slice(arg: &str) {
    println!("{}", arg);
}

fn string(arg: String) {
    println!("{}", arg);
}

pub fn run() {
    string_slice("blue");
    string("red".to_string());
    string(String::from("hi"));
    string("rust is fun!".to_owned());
    string("nice weather".into());
    string(format!("Interpolation {}", "Station"));
    string_slice(&String::from("abc")[0..1]);
    string_slice("  hello there ".trim());
    string("Happy Monday!".to_string().replace("Mon", "Tues"));
    string("mY sHiFt KeY iS sTiCkY".to_lowercase());
}

How Does Rust Make Me a Better Programmer?

Types Are Not Suggestions Anymore

  • Datatypes really matter
  • Trait or interface-oriented programming teaches you to think in terms of what an object can do and not what it is

Variable Scope Awareness

I’ve never thought about how my variables move in and out of scopes before:

  • Closures are fun
  • Having control over which parts of your code can and cannot modify your variables lets you think in a way you haven’t before

Accounting for Everything

I need to account for everything I’ve written:

  • When I use an enum variant in a match statement, I need to match for each and every case
  • I need to account for errors in the same way
  • I can define functions as having a return value that must be used and not ignored

How Do I…?

Common questions new Rustaceans ask:

The Rust ecosystem has excellent crates (libraries) for all of these use cases, and crates.io is the central repository.

Resources

Here are the resources I recommend for learning Rust:

Essential Resources

  1. The Rust Book (Official Docs)
  2. A Half-Hour to Learn Rust (Blog Article)
  3. Rustlings - Interactive Exercises (Official companion exercises)
  4. Let’s Get Rusty - The Rust Lang Book (Videos)

Books

  1. Rust in Action
  2. Rust for Rustaceans
  3. Zero to Production in Rust

Academic Resources

  1. CS 4414 - Operating Systems - Using Rust for an Undergrad OS Course (Reasons to Use Rust)

Code Examples

  1. The example code and project structure from this talk

Conclusion

Rust embodies the Python principle of “explicit is better than implicit” in a way that makes you think differently about programming. While it has a steep learning curve, it teaches valuable concepts about memory management, type safety, and error handling that make you a better programmer overall.

The key is not to abandon Python, but to add Rust as another tool in your toolkit for problems where its strengths shine: systems programming, performance-critical applications, and anywhere you need the confidence that comes with compile-time guarantees.

Related Posts: