Created
February 26, 2019 06:52
-
-
Save smilingleo/9983eafa3b1dc22a4c129fe24ee31983 to your computer and use it in GitHub Desktop.
Learning Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 = # | |
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