python to rust: the basics
The following shows Rust code and equivalent code in Python. Disclaimer: the following is not guaranteed to work as is (in fact most likely won’t).
variables
// foo = 'a'
let foo: char = 'a';
// to allow variable to be modified
let mut foo: i8 = 1;
// const must be initialised where as regular variables can be declared at first (but not common)
// can't be a function and can be global
const FOOBAR: u32 = 1;
// stating the obvious, but Rust is a statically typed language so we need to set a type when
// declaring a variable. In some cases, it's fine to not provide type and compiler will choose
// based on initial value but not necessarily optimally.
let integer = 1;
// can set variables without explicit function. below set y to whatever x is
let y = {
let mut x = 0;
// code
x // note missing semi-colon
};
data types
tuples
// tup = (1, 2 '2')
let tup = (1u8, 2u16, '2');
// indexing
// tup[1]
tup.1;
// slicing
// tup[:2]
// from what i can tell, tuples aren't meant for slicing/iterating
// more like an namedtuple in python (without the name)
array
// i don't use array lib in python
// arr = numpy.arange(1, 6, dtype=numpy.int32)
let arr: [i32; 5] = [1, 2, 3, 4, 5];
// arr = numpy.zeros(500, dtype=numpy.int32)
let arr: [u32; 500] = [0; 500];
// indexing
// arr[0]
arr[0];
// slicing
// arr[1:4]
&arr[1..4];
// len(arr)
arr.len();
std lib types
string
In Rust there are String
and &str
. The latter is most aligned with python as in python strings are immutable.
// value = "the quick brown fox"
let value = "the quick brown fox";
let mut string = String::new();
for c in chars {
// Insert a char at the end of string
string.push(c);
// Insert a string at the end of string
string.push_str(", ");
}
vector/list
vectors appear to be similar to lists in python as in their size is dynamic
// values = list(range(10))
// values = [1, 2, 3]
let values: Vec<i32> = (0..10).collect();
let mut values = vec![1, 2, 3];
// values.append(4)
// values.pop()
values.push(4);
values.pop();
// values[2]
// len(values)
values[2];
values.len();
// for i in values:
// print(i)
for i in values.iter() {
println!("{:?}", i);
}
// into_iter() will effectively throw away values from vec as it iterates
// iter_mut() allows code to modify the `i`
hashmap
// hm = dict()
use std::collections::HashMap;
let mut hm = HashMap::new();
// hm['foo'] = 'bar'
// hm['foo']
hm.insert("foo".to_string(), "bar".to_string());
hm["foo"]
// 'value' in hm
hm.contains_key("value")
// if 'value' not in hm:
// hm['value'] = 'hi'
hm.entry("value").or_insert("hi".to_string())
set
// values = set()
use std::collections::HashSet;
let mut values = HashSet::new();
// values.add('blah')
values.insert("blah".to_string())
// 'foo' in values
values.contains("foo")
casting
// blah = 32.1
// blah = int(blah)
let blah = 32.1;
let blah = blah as u16;
// chr(32)
let int_as_char = 32 as char;
// casting to lower type will cropped to max
let blah = 300.0_f32 as u8; // will return 255
flow
if/else
// if value == 1:
// print("hi")
// elif value == 2:
// print("bye")
// else:
// print("leave now")
if value == 1 {
println!("hi");
} else if value == 2 {
println!("bye");
} else {
println!("leave now");
}
switch/case/match
// only exist in python3.10
match value {
1 => println!("hi"),
2 => println!("bye"),
x if x > 0 => println!("can add guard for additional conditional"),
x @ 3 .. 10 => println!("can bind with @ to get access to value {}", x),
_ => println!("leave now"),
}
loops
for
// for i in range(1, 100):
// print(i)
for i in 1..100 {
println!("{}", i);
}
while
// while True:
// print("hi")
// break
loop {
println!("hi");
break;
}
// x = 0
// while x < 5:
// print(x)
// x += 1
let mut x = 0
while x < 5 {
println!("{}", x);
x += 1;
}
iterating
// any(i for i in arr if i == 2)
arr.iter().any(|&x| x == 2)
// value = None
// for i in arr:
// if i == 2:
// value = i
// break
value = arr.iter().find(|&x| *x == 2)
// pos = None
// for count, i enumerate(arr):
// if i == 2:
// pos = count
// break
value = arr.iter().position(|&x| x == 2)
more
// break multiple loops
'outer: loop {
println!("Entered the outer loop");
'inner: loop {
println!("Entered the inner loop");
// This breaks the outer loop as well
break 'outer;
}
// return a value. below sets result = "value"
let result = loop {
// something
break "value";
}
functions
// def do_something(foo: int, bar: int) -> bool
// return False
// value = 1
// do_something(value, 2)
fn do_something(foo: i32, bar: i32) -> bool
return false; // or false
do_something(&value, 2) // see ownership for `&`
lambdas/closures
// something = lambda x: x
let something = |x: i32| -> i32> { x };
// something = lambda x: x.append(1)
// add move to modify the input parameter
let something = move |x: Vec<i32>| -> () { x.push(1); };
“classes”
// class Something:
// x: int
// y: int
// def does_nothing(self):
// pass
struct Something {
x: i64,
y: i64,
}
impl Something {
fn does_nothing(&self) -> () {
// if self not included, it is a static method
// &mut self to modify object variables. object itself must be mutable as well.
}
}
scope
let x = 1;
{
println!("Can see x's value: {}" , x);
let y = 2;
}
println!("Cannot see y here");
{
let x = 3;
// x is 3 here
}
println!("x is still 1");
// not affected by variable shadowing in previous block
self::<func|struct>
to call item in same modulesuper::<func|struct>
to call item in parent scopecrate::<func|struct>
to call item in crate scopepub <use|fn|mod|struct>
to all access outside current module
modules
import/use
// from a.b.c import d, e
// from a.b.c import *
// from a.b.c import d as newname
use a::b::c::{d, e};
use a::b::c::*;
use a::b::c::d as newname;
ownership
// only one variable can own a value
let s1 = String::from("asdf");
let s2 = s1;
// s1 no longer has ownership and can't access string
// doesn't apply to primitives like int/float/bool which will create a copy
let int1 = 1;
let int2 = int2;
// int1 and int2 are both valid variables at this point
// only one variable can borrow a value
let s3 = &mut s2;
let s4 = &s2;
// let s5 = &mut s2 will fail
debugging
// print(f'the value of x is {x}')
// if non-primitive type, neeed to implement Display
// impl fmt::Display for CustomStruct {
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// write!(f, "{}", self.0)
// }
// }
println!("the value of x is {}, x);
// debugger printing
// closer to print(f'the value of x is {repr(x)}')
// if x is a non-primitive type, need to 'decorate' the struct with `#[derive(Debug)]` to print
println!("the value of x is {:?}", x);
TODO: add details on debugger (if it exists)
packaging
// poetry new my-package
cargo new my-package