py2rs

From Python into Rust

let x = Rust::from("Python");

A quick reference guide for the Pythonista in process of becoming a Rustacean.

image_2017-11-28_08-03-59

Monty Python - Season 3 - Episode 49

The sketch

Mrs. Jalin: George.
Mr. Jalin: Yes, Gladys.
Mrs. Jalin: There's a man at the door with a moustache.
Mr. Jalin: Tell him I've already got one. (Mrs. Jalin hits him hard with a newspaper) 
          All right, all right. What's he want then?
Mrs. Jalin: He says do we want a documentary on crustaceans.
Mr. Jalin: Crustaceans!
Mrs. Jalin: Yes.
Mr. Jalin: What's he mean, crustaceans?
Mrs. Jalin: CRUSTACEANS!! GASTROPODS! LAMELLIBRANCHS! CEPHALOPODS!
...

Ok... watch it later... let's learn some Rust now...

Getting Started with Rust

Assuming you already know what is Rust and already decided to start learning it. Here are some steps for you to follow:

  1. Take a tour of Rust Syntax and Coding Style and Tour if Rust
  2. Watch some screencasts to get basics of Ownership &Borrowing concept
    http://intorust.com/ or if you understand Portuguese watch Aprenda Rust
  3. Follow this set of runnable examples to understand how everything fit together
    https://doc.rust-lang.org/stable/rust-by-example/
  4. Now it is time to read your first book, you can pick:
  5. Read some real examples
    • Rust Cookbook This Rust Cookbook is a collection of simple examples that demonstrate good practices to accomplish common programming tasks, using the crates of the Rust ecosystem.
    • Anthology
  6. Patterns and Good Practices

Exercises

Time to put your new knowledge in action solving some exercises.

  1. Exercism.io
    Register a new account on exercism.io (using github auth)
    Install exercism command line client on your computer
    Solve some exercises: https://www.exercism.io/languages/rust/

  2. Rust Playground
    Run Live Rust Code in the browser with https://play.rust-lang.org/

  3. Rustlings Small exercises to get you used to reading and writing Rust code. Clone the repo and follow the guide. This is a great way to get used to dialogue with the compiler. Interactive rust exercises: https://github.com/rust-lang/rustlings

Getting updated

Now I assume you are addicted to Rust and you want to be updated about everything around it, here are some good links to follow.

  1. This Week in Rust Newsletter
    https://this-week-in-rust.org/

    https://twitter.com/thisweekinrust

  2. Awesome Rust Newsletter
    https://rust.libhunt.com/

  3. Reddit
    http://reddit.com/r/rust (serious sub-reddit)
    http://reddit.com/r/rustjerk (almost memes only)

  4. Official Twitter
    https://twitter.com/rustlang

Interact with other Rustaceans

Don't be afraid, the Rustaceans are a very receptive species and are cozy with the Pythonistas.

https://www.rust-lang.org/en-US/community.html

Local Communities

Additional learning resources

Facts

  • The language is named Rust because "rust is as close to the bare metal as you can get".,
    in metal theory rust is the chemical layer closest to bare metal.
    (also Wikipedia says that the name was possibly inspired by the name of a Fungi)
  • The Rust trifecta is 1) Memory Safe, 2) Fast 3) Concurrent
  • Rust can be used for web development
  • Rust can be used for Gaming Development
  • Rust can be used for Machine Learning
  • Lots of IDEs and Editors supports Rust (VSCode is known to have the better support by now)
  • Rust packages are called Crates and are installed by Cargo explore them at http://crates.io
  • In Rust there is no Class but Structs, Enums, Traits, functions and macros!
  • Rust compiler was first written in OCaml then rewritten in Rust! (Rust is written in Rust!!!)
  • Rust type system is strongly inspired by Haskell
  • Rust functional style is inspired by Erlang
  • Rust type inference is mainly inspired by ML and also by Haskell
  • The main syntax style is inspired by C and C++
  • There is no automated Garbage Collector so Rust frees memory based on Resource Aquisition RAII (a.k.a Ownership)
  • Rust has Generic Types!!!
  • As Rust is close to bare metal you can ship a program without the inclusion of Rust's runtime which makes easy to distribute programs (no need of dependencies and virtuelenvs management)
  • Graydon Hoare (creator of Rust) is now working at Apple developing the Swift language
  • Rust is the developers most loved language according to Stack Overflow Survey
  • Rust is the most energy efficient language! and that is very important for environment, data center companies and maybe it can help saving your laptop and phone battery in near future.
  • There is an Operating System written in Rust - Redox
  • Mozilla released the fastest version of Firefox (quantum) having many parts written on Rust
  • The Rust mascot (unofficial) is called Ferris and it is a crab (There is no record of the official reason about being a crab, the reasonable history is that it was inspired by the Rusty Crab a common species of crab and also a name of a famous restaurant.)
  • To compliment your fellow Rustaceans don't say cheers!. Say safe! (safe! is also said when toasting with champagne at Rust conferences)
  • Rust is to become a second programming language for the Linux kernel (see here)
  • Rust is the language choosen by Microsoft to rewrite parts of Windows Kernel

More facts? and curiosities send a question here or send a Pull Request adding an interest fact to this list.

ferris

Glossary of terms

TermDefinition
crateA rust distributable package
ferrisThe unofficial Crab Mascot
RustaceanThe Rust programmer or evangelist or enthusiastic
nightlyThe unstable toolchain of the Rust compiler
implImplementation

General

PythonDefinitionRust
PEP8Guidelines and conventionsRustAPI Guidelines
PEPSEnhancement Proposals / RFCRust RFCs
PSFOrganization / Foundation[Rust Foundation](https://foundation.rust-lang.org/
PyConMain ConferenceRustConf
Guido Van RossumCreatorGraydon Hoare
1989First appeared2010
1991First Release2012
PSFLicenseApache 2.0 and MIT
CImplemented inRust
.py, .pyw, .pycFile Extensions.rs, .rlib
http://github.com/python/cpythonRepositoryhttps://github.com/rust-lang/rust
Pyladies, AfroPythonDiversity and Inclusion initiativeRustBridge
comp.lang.PythonOfficial Users Forumusers.rust-lang.org

Environment Tools

PythonDefinitionRust
requirements.txtOfficial dependency tracker fileCargo.toml
setup.pyOfficial installator / distributor fileCargo.toml
PyPILibrary repositoryCrates.io
pipLibrary installationCargo
setuptools and poetryLibrary distributionCargo
pbrLibrary distributionCargo
pipenv and poetryDependency managerCargo
twinePackage uploaderCargo and Semantic
venv *Isolated environmentsCargo
pyinstallerGenerate standalone executablesCargo
pyenvInstall and manage versions of languagerustup
pydoc and sphinxGenerate documentation from coderustdoc and Cargo
pythonInterpreter / Compilerrustc and Cargo
ipythonREPLiRust
ipdbDebuggerrust-gdb
Extending Python with C or C++Foreign language interfacePyO3

Libraries and Frameworks

PythonDefinitionRust
urllib *HTTP callshyper
requestsSimplified HTTP callsreqwest
jsonJSON parsing loading and dumpingserde
pyYAMLYAML parsing loading and dumpingserde
lxmlXML parsing loading and dumpingRustyXML
csv *CSV parsingrust-csv
datetime * & DateutilsDate & timeChrono
click and argparseCLI Frameworkclap
docoptCLI Frameworkdocopt
re *Regular Expressionsregex
subprocess *Run external commandssubprocess
multiprocessing *MultiprocessingRayon
logging *Logginglog
Pathlib *Path manipulationfs and fs_extra
cryptographyCrytographycrypto
pickle *Object serializationRON
heapq *Heap queueBinaryHeap *
bottleMinimal web frameworkIron
flaskWeb frameworkRocket
djangoFull stack web frameworkDO NOT EXIST YET
SQL AlchemyRelational database ORMDiesel
PymongoMongoDB drivermongodb
Jinja 2Template engineTera
pygtkGTk desktop developmentgtk
pysideQT desktop developmentrust-qt
pygame2D UI library / gamingggez & Conrod & Piston
unitest2Test frameworkBuiltin
noseTest runnerCargo
pytestTesting framework and runnerPolish
Flake8LinterClippy
autopep8 and blackAuto formatterrustfmt
twistedNetwork application frameworklibpnet
AsyncIO *Async application frameworkTokio and futures
PillowImage manipulationImage
Beautiful SoupHTML parserhtml5ever
HypothesisData driven test frameworkQuickcheck and proptest
mockTest mockingMockers
bioPythonBioinformathics librariesRust Bio
DynaconfConfig managementConfig
itertools *Data structure iterationRust Itertools
GeopythonGeo spatial dataGeo Rust
ScikitLearnMachine learningrusty-machine
mistuneMarkdown / Common Mark Parsercmark
celeryDistributed computationAntimony
botoAWS clientsrusoto
AstroPyAstronomyastro-rust
NumpyNumericNumeric
PandasDataframesPolars

Applications

PythonDefinitionRust
PelicanStatic Site generatorCobalt
ansibleInfra Orchestrationrealize
mkdocsGenerate documentation and e-books from MarkdownmdBook
locustHTTP load testdrill
NamekoMicroservices Frameworkfractalide
Quokka CMSCMSNickel CMS

Useful crates

Add Pythonic features to Rust

PythonDefinitionRust
{'foo': "bar"}Syntax to create a dict / hashmapmaplit
__init__(self, value='default')Instance initialization (with some default values)derive_new
itertools *stdlibExtra iterators methodsitertools
hashlib *Password Hashinglibpasta

Show me The code

From Python to Rust by examples

You can copy-paste and run the Rust examples in https://play.rust-lang.org/ and Python in https://repl.it/languages/python3

Creating a new project

Create a new project with basic files, entry points, module initializer, dependency and installation artifacts.

Python

$ mkdir {pyproject,pyproject/src}
$ touch {pyproject/src/{__init__.py,__main__.py,program.py},pyproject/{requirements.txt,setup.py}} 
$ echo "-e ." >> pyproject/requirements.txt
$ echo "from setuptools import setup" >> pyproject/setup.py
$ echo "setup(author=..., name=...)" >> pyproject/setup.py

Rust

#![allow(unused)]
fn main() {
$ cargo new my-rust-program
}

Installing new libraries/crates

Python

$ pip install foo 

Rust

$ cargo install foo

running--compiling

Python

$ python my_python_program.py 

Rust

$ cargo run

In Rust, there is a --release flag that allows for more compile time optimization to be done, but it will take longer to compile

$ cargo run --release

Hello World

Python

if __name__ == "__main__":
    print("Hello, World")

Rust

fn main() {
  println!("Hello, World");
}

Types and Declarations

Create new objects, values on basic primitive types and also data structures.

Python

age = 80
name = 'daffy'
weight = 62.3
loons = ['bugs', 'daffy', 'taz']
ages = {  # Ages for 2017
    'daffy': 80,
    'bugs': 79,
    'taz': 63,
}

Rust

use std::collections::HashMap;

fn main() {
    let age = 80;
    let name = "daffy";
    let weight = 62.3;
    let mut loons = vec!["bugs", "daffy", "taz"];

    let mut ages = HashMap::new();  // Ages for 2017
    ages.insert("daffy", 80);
    ages.insert("bugs", 79);
    ages.insert("taz", 63);
}

Define a function

Defining a function that takes 2 integer arguments and returns its sum.

Python

def add(a, b):
    """Adds a to b"""
    return a + b

Python with typing annotations

It looks more similar to Rust.

def add(a: int, b: int) -> int:
    """Adds a to b"""
    return a + b

Rust

#![allow(unused)]
fn main() {
/// Adds a to b
fn add(a: i32, b: i32) -> i32 {
  a + b
}
}

List/Slice

Creating a list, adding new elements, gettings its length, slicing by index, iterating using for loop and iterating with enumerator.

Python

names = ['bugs', 'taz', 'tweety']
print(names[0])  # bugs
names.append('elmer')
print(len(names))  # 4
print(names[2:])  # ['tweety', 'elmer']

for name in names:
    print(name)

for i, name in enumerate(names):
    print('{} at {}'.format(name, i))

Rust

fn main() {
    let mut names = vec!["bugs", "taz", "tweety"];
    println!("{}", names[0]);  // bugs
    names.push("elmer");
    println!("{}", names.len());  // 4
    println!("{:?}", &names[2..]);  // ["tweety", "elmer"]

    for name in &names {
        println!("{}", name);
    }

    for (i, name) in names.iter().enumerate() {
        println!("{} at {}", i, name);
    }
}

.step_by() is the equivalent for python's range/xrange step parameter.

python:

for i in range(0,10,2):
   print(i) # 0, 2, 4, 6, 8

rust:

#![allow(unused)]
fn main() {
for i in (0..10).step_by(2) {
    println!("{}", i);  // 0, 2, 4, 6, 8
}
}

Dict/Map

Create new dictionaries (hash maps), adding new keys and values, changing values, getting by key, checking if a key is containing, etc.

Python


# Creating a new dict and populating it
ages = {}
ages['daffy'] = 80
ages['bugs'] = 79
ages['taz'] = 63

# or doing the same using a for loop
ages = {}
for name, age in [("daffy", 80), ("bugs", 79), ("taz", 63)]:
    ages[name] = age

# or initializing from a list
ages = dict([("daffy", 80), ("bugs", 79), ("taz", 63)])

# or passing key values on creation
ages = {  # Ages for 2017
    'daffy': 80,
    'bugs': 79,
    'taz': 63,
}

ages['elmer'] = 80
print(ages['bugs'])  # 79
print('bugs' in ages)  # True

del ages['taz']

for name in ages:  # Keys
    print(name)

for name, age in ages.items():  # Keys & values
    print('{} is {} years old'.format(name, age))

Rust

use std::iter::FromIterator;
use std::collections::HashMap;

fn main() {

    // Creating a new HashMap and populating it
    let mut ages = HashMap::new();  // Ages for 2017
    ages.insert("daffy", 80);
    ages.insert("bugs", 79);
    ages.insert("taz", 63);

    // or doing the same using a loop
    let mut ages = HashMap::new();
    for &(name, age) in [("daffy", 80), ("bugs", 79), ("taz", 63)].iter() {
        // For non-Copy data, remove & and use iter().clone()
        ages.insert(name, age);
    }

    // or initializing from Array
    let mut ages: HashMap<&str, i32> =  // Ages for 2017
        [("daffy", 80), 
         ("bugs", 79), 
         ("taz", 63)]
        .iter().cloned().collect();

    // or initializing from Vec (Iterator)
    let mut ages: HashMap<&str, i32> =  // Ages for 2017
        HashMap::from_iter(
            vec![
               ("daffy", 80),
               ("bugs", 79),
               ("taz", 63)
            ]
        );

    ages.insert("elmer", 80);
    println!("{}", ages["bugs"]);  // 79
    println!("{}", ages.contains_key("bugs")); // true
    ages.remove("taz");


    for name in ages.keys() {  // Keys
      println!("{}", name);
    }

    for (name, age) in &ages {  // Keys & values
      println!("{} is {} years old", name, age);
    }

}

Pythonic alternative to dict/map in Rust

You can use the maplit crate to load hashmap! macro to have an efficient sugared (a.k.a Pythonic) syntax!

# Cargo.toml
[dependencies]
maplit = "*"

then

#![allow(unused)]
fn main() {
#[macro_use] extern crate maplit;

let map = hashmap!{
    "daffy" => 80,
    "bugs" => 79,
    "taz" => 63,
};
}

set / HashSet

Create a set (a hash of unique keys), add new keys and compute intersection, difference and union

Python


# creating and populating
colors = set()
colors.add("red")
colors.add("green")
colors.add("blue")
colors.add("blue")

# using literal syntax
colors = {'red', 'green', 'blue', 'blue'}

# from an iterator
colors = set(['red', 'green', 'blue', 'blue'])


# deduplication
print(colors)  # {"blue", "green", "red"}

# operations
colors = {'red', 'green', 'blue', 'blue'}
flag_colors = {"red", "black"}

# difference
colors.difference(flag_colors)  # {'blue', 'green'}

# symmetric difference
colors.symmetric_difference(flag_colors)  # {'black', 'blue', 'green'}

# intersection
colors.intersection(flag_colors)  # {'red'}

# union
colors.union(flag_colors)  # {'black', 'blue', 'green', 'red'}

Rust

use std::collections::HashSet;
use std::iter::FromIterator;

fn main() {

    // creating and populating - type inference
    let mut colors = HashSet::new();
    colors.insert("red");
    colors.insert("green");
    colors.insert("blue");
    colors.insert("blue");

    // from an iterator - explicit type
    let mut colors: HashSet<&str> = HashSet::from_iter(vec!["red", "green", "blue", "blue"]);

    // deduplication
    println!("{:?}", colors); // {"blue", "green", "red"}

    // Operations
    let mut colors: HashSet<&str> = HashSet::from_iter(vec!["red", "green", "blue", "blue"]);
    let mut flag_colors: HashSet<&str> = HashSet::from_iter(vec!["red", "black"]);

    // difference
    colors.difference(&flag_colors); // ["green", "blue"]

    // symmetric difference
    colors.symmetric_difference(&flag_colors); // ["blue", "green", "black"]

    // intersection
    colors.intersection(&flag_colors); // ["red"]

    // union
    colors.union(&flag_colors); // ["red", "blue", "green", "black"]
}

or syntax sugared using maplit crate

#![allow(unused)]
fn main() {
#[macro_use] extern crate maplit;

let colors = hashset!{"red", "green", "blue", "blue"};
}

while and for loops

Looping until a condition is met or over an iterable object.

Python

# While loop

counter = 0
while counter < 10:
    print(counter)
    counter += 1

# infinite while loop
while True:
    print("loop Forever!")

# infinite while loop with break
counter = 0
while True:
    print(counter)
    counter += 1
    if counter >= 10:
        break


# while loop with continue
counter = 0
while True:
    counter += 1
    if counter == 5:
        continue
    print(counter)
    if counter >= 10:
        break

# For loop over a list
for color in ["red", "green", "blue"]:
    print(color)

# Enumerating indexes
for  i, color in enumerate(["red", "green", "blue"]):
    print(f"{color} at index {i}")

# For in a range
for number in range(0, 100):
    print(number)  # from 0 to 99

Rust

fn main() {

    // While loop
    let mut counter = 0;
    while counter < 10 {
        println!("{}", counter);
        counter += 1;
    }

    // infinite while loop
    loop {
        println!("Loop forever!");
    }

    // infinite while loop with break
    let mut counter = 0;
    loop {
        println!("{}", counter);
        counter += 1;
        if counter >= 10 { break; }
    }

    // infinite while loop with continue
    let mut counter = 0;
    loop {
        counter += 1;
        if counter == 5 { continue; }
        println!("{}", counter);
        if counter >= 10 { break; }
    }

    // for loop over a list
    for color in ["red", "green", "blue"].iter() {
        println!("{}", color);
    }

    // Enumerating indexes
    for (i, color) in ["red", "green", "blue"].iter().enumerate() {
        println!("{} at index {}", color, i);
    }

    // for in a range
    for number in 0..100 {
        println!("{}", number);  // from 0 to 99
    }
}

Loop Labels

Rust has a looping feature which is not present on Python: Loop labels

#![allow(unused)]
fn main() {
'outer: for x in 0..10 {
    'inner: for y in 0..10 {
        if x % 2 == 0 { continue 'outer; } // continues the loop over x
        if y % 2 == 0 { continue 'inner; } // continues the loop over y
        println!("x: {}, y: {}", x, y);
    }
}
}

Files

Read a text file and iterate its lines printing the content, properly close the file at the end.

Python

from pathlib import Path

with Path("/tmp/song.txt").open() as fp:
    #  Iterate over lines
    for line in fp:
        print(line.strip())

Rust

use std::io::{BufReader, BufRead};
use std::fs::File;
use std::path::Path;


fn main () {
    let fp = File::open(Path::new("/tmp/song.txt")).unwrap();
    let file = BufReader::new(&fp);
    for line in file.lines() {
        //  Iterate over lines
        println!("{}", line.unwrap());
    }
}

Exceptions/Return Error

Expecting for exceptions and identifying errors.

Python

def div(a, b):
    if b == 0:
        raise ValueError("b can't be 0")
    return a / b

# ...

try:
    div(1, 0)
except ValueError:
    print('An error occurred!')

Rust

fn div(a: i32, b: i32) -> Result<i32, &'static str> {
    if b == 0 {
        Err("b can't be 0")
    } else {
        Ok(a / b)
    }
}

fn main() {
    match div(1, 0) {
        Ok(_) => {},
        Err(_) => println!("An error occurred!"),
    };
}

Concurrency

Python

thr = Thread(target=add, args=(1, 2), daemon=True)
thr.start()

Rust

#![allow(unused)]
fn main() {
use std::thread;

thread::spawn(|| {
        add(5,5);
    });

}

Communicating between threads

Managing data context between threads.

Python

from queue import Queue
queue = Queue()
# ...
# Send message from a thread
queue.put(353)


# ...
# Get message to a thread
val = queue.get()

Rust

use std::thread;
use std::sync::mpsc;

fn main() {
    let (tx, rx) = mpsc::channel();

    let sender = thread::spawn(move || {
        let val = String::from("hi");
        tx.send(val.clone()).unwrap();
        println!("Sent {}", val);
    });

    let receiver = thread::spawn(move || {
        let received = rx.recv().unwrap();
        println!("Received: {}", received);
    });

    sender.join();
    receiver.join();
}

Sorting

Sorting lists, reversing and using a key.

Python

names = ['taz', 'bugs', 'daffy']

# Lexicographical order
names.sort()

# Reversed lexicographical order
names.sort(reverse=True)

# Sort by length
names.sort(key=len)

Rust

fn main() {
    let mut names = ["taz", "bugs", "daffy"];

    // Lexicographical order
    names.sort();

    // Reversed lexicographical order
    names.sort_by(|a, b| b.cmp(a));

    // Sort by length
    names.sort_by_key(|a| a.len());
}

Web app with Flask / Rocket

Python

from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    return 'Hello Python'


if __name__ == '__main__':
    app.run(port=8080)

Rust

#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "Hello Rust"
}

fn main() {
    rocket::ignite().mount("/", routes![index]).launch();
}

HTTP Request with error handling

Python

Using requests

import requests

url = 'https://httpbin.org/ip'

try:
    resp = requests.get(url)
except HTTPError as err:
    msg = f"error: cannot get {url} - {err}"
    raise SystemExit(msg)

assert resp.status_code == 200

print(f"The response content is: {resp.content}")

Rust

using reqwest

extern crate reqwest;
use std::io::Read;

fn main() {
    let url = "https://httpbin.org/ip";

    let mut resp = match reqwest::get(url) {
        Ok(response) => response,
        Err(e) => panic!("error: could not perform get request {}", e),
    };

    assert!(resp.status().is_success());

    let mut content = String::new();
    resp.read_to_string(&mut content).expect("valid UTF-8");

    println!("The response content is: {}", content);
}

Multithreaded HTTP Crawler

Python

Using requests

from concurrent.futures import ThreadPoolExecutor
import requests


URLS = (
    "https://httpbin.org/html",
    "https://httpbin.org/links/10/0",
    "https://httpbin.org/robots.txt",
    "https://httpbin.org/user-agent",
    "https://httpbin.org/links/10/0",
    "https://httpbin.org/robots.txt",
    "https://httpbin.org/xml",
    "https://httpbin.org/redirect/1",
    "https://httpbin.org/redirect/2",
    "https://httpbin.org/cookies",
    "https://httpbin.org/basic-auth/user/passwd",
    "https://httpbin.org/gzip",
)


def crawl_worker(url):
    try:
        print(f"Response of url: {url} is {requests.get(url).status_code}")
    except Exception:
        print("Failed to get url.")


if __name__ == "__main__":
    with ThreadPoolExecutor() as executor:
        executor.map(crawl_worker, URLS)

Rust

using reqwest

extern crate reqwest;
use std::thread;


fn crawl_worker(url: &str) {
    let parsed_url = reqwest::Url::parse(url).expect("Bad url format.");
    let response = reqwest::get(parsed_url).expect("Failed to get url.");
    println!("Response of url: {} is {:?}", url, response.status().to_string());
}


fn main() {
    let urls = vec![
        "https://httpbin.org/html",
        "https://httpbin.org/links/10/0",
        "https://httpbin.org/robots.txt",
        "https://httpbin.org/user-agent",
        "https://httpbin.org/links/10/0",
        "https://httpbin.org/robots.txt",
        "https://httpbin.org/xml",
        "https://httpbin.org/redirect/1",
        "https://httpbin.org/redirect/2",
        "https://httpbin.org/cookies",
        "https://httpbin.org/basic-auth/user/passwd",
        "https://httpbin.org/gzip",
    ];
    let mut queue = vec![];

    for url in urls {
        queue.push(thread::spawn(move || {
            crawl_worker(url);
        }));
    }

    for job in queue {
        let _ = job.join();
    }
}

Encode and Decode JSON

Python

import json

# Decode/Deserialize
data = '''{
    "name": "bugs",
    "age": 76
}'''

person = json.loads(data)

# Do things like with any other Python data structure
print(f"{person['name']} was born {person['age']} years ago")

# Encode/Serialize
serialized = json.dumps(obj)
print(f"The serialized value is: {serialized}")

Rust

extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

#[derive(Serialize, Deserialize)]
struct Person {
    name: String,
    age: u8,
}

fn main() {
    // Decode/Deserialize
    let data = r#"{"name": "bugs", "age": 76}"#;

    let p: Person = match serde_json::from_str(data) {
        Ok(person) => person,
        Err(e) => panic!("error: could not deserialize: {}", e),
    };

    // Do things just like with any other Rust data structure.
    println!("{} was born {} years ago.", p.name, p.age);

    // Encode/Serialize
    let serialized = serde_json::to_string(&p).unwrap();
    println!("The serialized value is: {}", serialized);
}

Object Orientation

Python

playground

class Cat:
    def __init__(self, name):
        self.name = name

    def greet(self, other):
        print("Meow {}, I'm {}".format(other, self.name))

# ...

grumy = Cat('Grumpy')
grumy.greet('Garfield')  # Meow Garfield, I'm Grumpy

Rust

playground

struct Cat {
    name: String
}

impl Cat {

    pub fn new<S>(name: S) -> Cat where S: Into<String> {
        Cat { name: name.into() }
    }
    
    pub fn greet<S: Into<String>>(&self, other:S) {
        println!("Meow {}, I'm {}", other.into(), self.name);
    }     
    
}

fn main() {
    let grumpy = Cat::new("Grumpy");
    grumpy.greet("Garfield");  // Meow Garfield, I'm Grumpy
}

NOTE: In Rust, it is best to avoid stringly types APIs so in the above example it would be better if we do let garfield = Cat::new("Garfield") and then make greet to accept an instance of Cat as other argument. If you are interested watch this.

Print formatted object debug information

Python


class Actor:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
      return str(self.__dict__)

daffy = Actor(
    name='Daffy',
    age=80,
)

print('{!r}'.format(daffy))  # {'name': 'Daffy', 'age': 80}

Rust

#[derive(Debug)]
struct Actor {
    name: String,
    age: i32
}

fn main() {
    let daffy = Actor {name: "Daffy".into(), age: 80};
    println!("{:#?}", daffy);   // Actor {name: "Daffy", age: 80 }
}

Operator overloading

Python and Rust allows the overload of the behavior of operators such as +, -, /, *, %

In both examples the operator + (add) is being overloaded to implement the Rock, Paper, Scissors game.

Python implementation uses its Protocol Oriented Programming, by looking for the __add__ method, which is part of the structural Summable protocol.

Rust does the same, but using trait implementation, in this case we implement ops::Add<T> for T

Both are, despite the syntax differences, very similar on the concept.

Python

playground

from enum import Enum
from typing import Self


class Object(Enum):
    Rock = 1
    Paper = 2
    Scissors = 3

    def __add__(self, other: Self) -> Self:
        match self:
            case Object.Rock if other is Object.Scissors:
                return self
            case Object.Scissors if other is Object.Paper:
                return self
            case Object.Paper if other is Object.Rock:
                return self
            case _:
                return other


if __name__ == "__main__":
    assert Object.Rock + Object.Scissors is Object.Rock
    assert Object.Scissors + Object.Paper is Object.Scissors
    assert Object.Paper + Object.Rock is Object.Paper
    assert Object.Rock + Object.Rock is Object.Rock
    assert Object.Paper + Object.Paper is Object.Paper
    assert Object.Scissors + Object.Scissors is Object.Scissors

Rust

playground

use std::ops;

#[derive(Debug, PartialEq)]
enum Object {
    Rock,
    Paper,
    Scissors,
}

impl ops::Add<Object> for Object {
    type Output = Object;
    fn add(self, other: Object) -> Object {
        match self {
            Object::Rock if other == Object::Scissors => self,
            Object::Scissors if other == Object::Paper => self,
            Object::Paper if other == Object::Rock => self,
            _ => other,
        }
    }
}

fn main() {
   assert_eq!(Object::Rock + Object::Scissors, Object::Rock);
   assert_eq!(Object::Scissors + Object::Paper, Object::Scissors);
   assert_eq!(Object::Paper + Object::Rock, Object::Paper);
   assert_eq!(Object::Rock + Object::Rock, Object::Rock);
   assert_eq!(Object::Scissors + Object::Scissors, Object::Scissors);
   assert_eq!(Object::Paper + Object::Paper, Object::Paper);
}

Template for new examples

Explanation comes here.

Python

playground

# python code goes here

Rust

playground

#![allow(unused)]
fn main() {
// rust code goes here
}

Credits

Created by Bruno Rocha @rochacbruno inspired by https://www.353.solutions/py2go/index.html

First published in BrunoRocha.org

Mdbook deploy and formatting by Rapha-Borges

Send a Pull Request or Suggestion as a new issue.


Contributors

Thanks goes to these wonderful people (emoji key):

This project follows the all-contributors specification. Contributions of any kind welcome!