Skip to content

Instantly share code, notes, and snippets.

@smilingleo
Created February 26, 2019 06:52
Show Gist options
  • Save smilingleo/9983eafa3b1dc22a4c129fe24ee31983 to your computer and use it in GitHub Desktop.
Save smilingleo/9983eafa3b1dc22a4c129fe24ee31983 to your computer and use it in GitHub Desktop.
Learning Rust
extern crate term;
use std::ops::Add;
fn main() {
test_unsafe();
}
// -------------
fn crate_test() {
let mut t = term::stdout().unwrap();
t.fg(term::color::GREEN).unwrap();
write!(t, "hello,").unwrap();
t.fg(term::color::RED).unwrap();
writeln!(t, "world!").unwrap();
t.reset().unwrap();
}
// -------
fn lifetime_test() {
let a = vec![1,2,3,4];
let b = vec![3, 4, 5];
let c = longer_vec(&a, &b);
println!("the length is {}", c.len());
}
// the compiler won't know which one will be returned, `x` or `y`
// and the returning value will also return the ownership, so we can tell
// the compiler these three variables (x, y, result) has same lifetime.
fn longer_vec<'a>(x: &'a[i32], y: &'a[i32]) -> &'a[i32] {
if x.len() > y.len() { return x } else { return y };
}
// ------------
#[derive(Debug)]
struct Tuple<T> {
first: T,
second: T,
}
fn generic_test() {
let t_u32: Tuple<u32> = Tuple { first: 4u32, second: 2u32 };
let t_u64: Tuple<u64> = Tuple { first: 5u64, second: 6u64 };
println!("{}", sum(t_u32));
println!("{}", sum(t_u64));
}
fn sum<T: Add<Output = T>>(t: Tuple<T>) -> T {
return t.first + t.second;
}
// ------
fn str_vs_String() {
// str is primitive type.
let s: &str = "hello";
// String is a struct.
let s2: String = "world".to_owned();
let s3: String = String::from("hello");
}
// --------
use std::fmt;
use std::error::Error;
// sum type
#[derive(Debug)]
enum OperationsError {
DivideByZeroError,
}
impl fmt::Display for OperationsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
OperationsError::DivideByZeroError => f.write_str("Cannot divide by zero"),
}
}
}
impl Error for OperationsError {
fn description(&self) -> &str {
match *self {
OperationsError::DivideByZeroError => "Cannot divide by zero",
}
}
}
fn divide(dividend: u32, divisor: u32) -> Result<u32, OperationsError> {
if divisor == 0u32 {
Err(OperationsError::DivideByZeroError)
} else {
Ok(dividend / divisor)
}
}
fn custom_errors() {
let result1 = divide(100, 0);
println!("{:?}", result1);
let result2 = divide(100, 2);
println!("{:?}", result2.unwrap());
}
// ---- syntactic macros
macro_rules! factorial {
// the compiler will simply replace the micro with right hand code of the arrow.
($x: expr) => {
{
let mut result = 1;
for i in 1..($x+1) {
result = result * i;
}
result
}
};
}
fn test_syntactic_marcos() {
let arg = std::env::args().nth(1).expect("Please provide only 1 argument");
// use `rustc -Z unstable-options --pretty expanded src/main.rs` to see the generated code.
println!("{:?}", factorial!(arg.parse::<u64>().expect("Could not parse to an integer")));
}
// -------- high order function
fn test_function_closure() {
let mut times = 2;
{
// This is in a new scope, the reason we have to put it in new scope
// is to prevent compiler complains the double borrow of `times` by
// `borrow` fn and `assert_eq` micro.
let mut borrow = |x| times += x;
borrow(5);
}
assert_eq!(7, times);
// `move` will `copy` the variable and then have the function owns
// that copied variable, so that the original value(own) doesn't change.
let mut own = move |x| times += x;
own(5);
assert_eq!(7, times);
}
// ------ concurrency
use std::thread;
use std::sync::mpsc; // multiple producer single consumer.
fn test_concurrency_with_channel() {
let rhs = vec![10, 20, 30, 40, 50, 60, 70];
let lhs = vec![1, 2, 3, 4, 5, 6, 7];
assert_eq!(rhs.len(), lhs.len());
let (sender, receiver) = mpsc::channel();
for i in 1..rhs.len() {
// since `Vec` doesn't implement `Copy` trait, it can't be copied by `move` automatically
// we need to manually clone the value, so that the compiler knows threads won't share the same vec.
let rhs = rhs.clone();
let lhs = lhs.clone();
// clone sender to have multiple senders
let sender = sender.clone();
let handle = thread::spawn(move || {
let s = format!("Thread {} added {} and {}, result {}", i, rhs[i], lhs[i], rhs[i] + lhs[i]);
sender.send(s).unwrap();
});
handle.join().unwrap();
}
// if you don't manually drop sender, the main thread won't exit.
drop(sender);
for result in receiver {
println!("{}", result);
}
}
// -------- unsafe
fn test_unsafe () {
// use unsafe to get rid of the overhead of smart pointer, or access Dereference raw pointer type `*const T`
let num: u32 = 42;
let p: *const u32 = &num;
unsafe {
// *p is unsafe operation.
assert_eq!(*p, num);
}
assert_eq!(p, &num);
println!("{:?}", p); // p is something like 0x7ffeee62ee34
}
// ------- test
// `cargo test` will run these unit tests.
#[cfg(test)]
mod tests {
#[test]
fn test_dummy() {
assert_eq!(1 + 1, 2);
}
}
#[test]
fn test_dumm2() {
assert_eq!(1 + 1, 2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment