$ cargo install rustfmt
$ cargo install racer
# Add to rutup
$ rustup component add rust-srcAt your Visual Studio Code settings, enable autofmt for Rust:
"[rust]": {
"editor.formatOnSave": true
}
- bool: Booleans
true,false - u8/u16/u32/u64: Fixed size unsigned integers
- i8, i16, i32, i64: Fixed size signed integers
- f32, f64: Fixed size floats
- usize: Architecture-dependant unsigned integer
- isize: Architecture-dependant signer integer
- char: Single unicode character
- str: String slice
- [T; N]: Fixed-size array. N number of T values
- &[T]: Slices
- (T1, T2, ...): Tuples
- fn(T1, T2, ...) -> R: Functions that take types
T1, T2, ...as parameters, returns value of typeR
pub fn sum(a: i8, b: i8) -> i8 {
a + b
}
#[cfg(test)]
mod tests {
// use sum;
fn sum_inputs_and_outputs() -> Vec<((i8, i8), i8)> {
vec![
((1, 2), 3),
((2, 3), 5),
((4, 5), 9)
]
}
#[test]
fn it_works() {
for (input, output) in sum_inputs_and_outputs() {
assert_eq!(::sum(input.0, input.1), output);
}
}
#[test]
#[ignore]
fn ignore_this_test() {
println!("tested");
assert!(true);
}
}If you are passing a string to a function, use the &str type - a string slice is an acceptable input parameter not only for actual string slice referefences but also for String references.
fn say_hello(to_whom: &str) {
println!("Hey {}", to_whom);
}
fn main() {
let string_slice: &'static str = "you";
let string: String = string_slice.into(); // Requet a new `String` type to be created from a string slice
say_hello(string_slice);
say_hello(&string);
}fn main() {
let mut empty_string = String::new();
let empty_string_with_capacity = String::with_capacity(50);
let string_from_bytestring: String =
String::from_utf8(vec![82, 85, 83, 84]).expect("Creating string from bytestring failed");
println!("empty_string: {}", empty_string);
println!(
"empty_string_with_capacity: |{}|",
empty_string_with_capacity
);
println!("string_from_bytestring: {}", string_from_bytestring);
empty_string.push('a');
println!(
"empty string is now {} with len {}",
empty_string,
empty_string.len()
);
empty_string.push_str("hi! world!");
println!(
"empty string is now {} with len {}",
empty_string,
empty_string.len()
);
}Output:
empty_string:
empty_string_with_capacity: ||
string_from_bytestring: RUST
empty string is now a with len 1
empty string is now ahi! world! with len 11
fn main() {
let mut integer_array_1 = [1, 2, 3];
let integer_array_2: [u64; 3] = [1, 2, 3];
let integer_array_3: [u64; 32] = [0; 32];
// let integer_array_4: [i32; 16438] = [-5; 16438];
integer_array_1[0] = 255;
println!("1: {:?}", integer_array_1);
println!("2: {:?}", integer_array_2);
println!("3: {:?}", integer_array_3);
// println!("4: {:?}", integer_array_4);
}Output:
1: [255, 2, 3]
2: [1, 2, 3]
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
use std::fmt::Debug;
fn print_slice<T: Debug>(slice: &[T]) {
println!("{:?}", slice);
}
fn main() {
let array: [u8; 5] = [1, 2, 3, 4, 5];
println!("Whole array just borrowed:");
print_slice(&array);
println!("Whole array sliced:");
print_slice(&array[..]);
println!("Without the first element:");
print_slice(&array[1..]);
println!("One element from the middle:");
print_slice(&array[3..4]);
println!("First three element:");
print_slice(&array[..3]);
println!("Oops, going too far");
print_slice(&array[..900]);
}Output:
Whole array just borrowed:
[1, 2, 3, 4, 5]
Whole array sliced:
[1, 2, 3, 4, 5]
Without the first element:
[2, 3, 4, 5]
One element from the middle:
[4]
First three element:
[1, 2, 3]
Oops, going too far
thread 'main' panicked at 'index 900 out of range for slice of length 5', src/libcore/slice/mod.rs:745:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.
#[derive(Debug)]
struct Money<T> {
amount: T,
currency: String,
}
fn main() {
let whole_euros: Money<u8> = Money {
amount: 42,
currency: "EUR".to_string(),
};
let floating_euros: Money<f32> = Money {
amount: 24.312,
currency: "EUR".to_string(),
};
println!("whole_euros: {:?}", whole_euros);
println!("floating_euros: {:?}", floating_euros);
}Output:
whole_euros: Money { amount: 42, currency: "EUR" }
floating_euros: Money { amount: 24.312, currency: "EUR" }
// Lets us overload the +operator
use std::ops::Add;
// pub trait Add<RHS = Self> { // trait has a generic type RHS that needs to be equal to the Self type
// type Output; // Any implementation needs to declare an `Output` type
// // Any implementations needs to implement an add method that takes a right-hand side parameter
// // that was declared on the first line to be the same as the `Self` type
// fn add(self, rhs: RHS) -> Self::Output;
// }
#[derive(Debug)]
struct Money<T> {
amount: T,
currency: String,
}
// impl<T: Add<T, Output=T>> says that our implementation has a generic type T
// Add for Money says we are implementing the Add trait for the type Money<T>
// <T: Add> says this has to implement the Add trait
// <T, Output=T> Furthermore, the implementation of the Add trait must have
// it's input and output types as the same
impl<T: Add<T, Output = T>> Add for Money<T> {
type Output = Money<T>;
fn add(self, rhs: Money<T>) -> Self::Output {
assert!(self.currency == rhs.currency);
Money {
currency: rhs.currency,
amount: self.amount + rhs.amount,
}
}
}
fn main() {
let rm10: Money<u8> = Money {
amount: 10,
currency: "RM".to_string(),
};
let rm50: Money<u8> = Money {
amount: 50,
currency: "RM".to_string(),
};
println!("{:?}", rm10 + rm50);
}
Output:
Money { amount: 60, currency: "RM" }
// This trait allows use to specify conversion methods from and to arbirary types
use std::convert::Into;
#[derive(Debug)]
struct Money<T> {
amount: T,
currency: String,
}
#[derive(Debug)]
struct CurrencylessMoney<T> {
amount: T,
}
impl<T> Into<CurrencylessMoney<T>> for Money<T> {
fn into(self) -> CurrencylessMoney<T> {
CurrencylessMoney {
amount: self.amount,
}
}
}
fn main() {
let rm10: Money<f32> = Money {
amount: 10.50,
currency: "RM".to_string(),
};
let currencyless: CurrencylessMoney<f32> = rm10.into();
println!("{:?}", currencyless);
// This will throw error
// type annotations required: cannot resolve `Money<f32>: std::convert::Into<_>`
// println!("{:?}", rm10.into());
}Output:
CurrencylessMoney { amount: 10.5 }
use std::fmt::{Display, Formatter, Result};
// pub trait Display {
// fn fmt(&self, &mut Formatter) -> Result<(), Error>;
// }
// #[derive(Debug)]
struct Money<T> {
amount: T,
currency: String,
}
impl<T: Display> Display for Money<T> {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{} {}", self.amount, self.currency)
}
}
fn main() {
let rm5: Money<i8> = Money {
amount: 10,
currency: "RM".to_string(),
};
print!("{}", rm5);
}Output:
10 RM%
use std::io::Read;
use std::path::Path;
use std::fs::File;
fn main() {
let path = Path::new("data.txt");
let mut file = match File::open(&path) {
Ok(file) => file,
Err(e) => {
println!("Error while opening file: {}", e);
panic!();
}
};
let mut s = String::new();
file.read_to_string(&mut s);
println!("Read the string: {}", s);
}use std::string::FromUtf8Error;
fn bytestring_to_string_with_match(str: Vec<u8>) -> Result<String, FromUtf8Error> {
match String::from_utf8(str) {
Ok(str) => Ok(str.to_uppercase()),
Err(err) => Err(err),
}
}
fn bytestring_to_string(str: Vec<u8>) -> Result<String, FromUtf8Error> {
String::from_utf8(str).map(|s| s.to_uppercase())
}
fn main() {
let faulty_bytestring = vec![130, 131, 132, 133];
let ok_bytestring = vec![80, 82, 84, 85, 86];
let s1_faulty = bytestring_to_string_with_match(faulty_bytestring.clone());
let s1_ok = bytestring_to_string_with_match(ok_bytestring.clone());
println!("s1_faulty: {:?}", s1_faulty);
println!("s1_ok: {:?}", s1_ok);
let s2_faulty = bytestring_to_string(faulty_bytestring.clone());
let s2_ok = bytestring_to_string(ok_bytestring.clone());
println!("s2_faulty: {:?}", s2_faulty);
println!("s2_ok: {:?}", s2_ok);
}use std::string::FromUtf8Error;
fn bytestring_to_string_with_match(str: Vec<u8>) -> Result<String, FromUtf8Error> {
let ret = match String::from_utf8(str) {
Ok(str) => str.to_uppercase(),
Err(err) => return Err(err),
};
Ok(ret)
}
fn bytestring_to_string_with_try(str: Vec<u8>) -> Result<String, FromUtf8Error> {
let ret = try!(String::from_utf8(str));
Ok(ret)
}
fn main() {
let faulty_bytestring = vec![130, 131, 132, 133];
let ok_bytestring = vec![80, 82, 84, 85, 86];
let s1_faulty = bytestring_to_string_with_match(faulty_bytestring.clone());
let s1_ok = bytestring_to_string_with_match(ok_bytestring.clone());
println!("s1_faulty: {:?}", s1_faulty);
println!("s1_ok: {:?}", s1_ok);
let s2_faulty = bytestring_to_string_with_try(faulty_bytestring.clone());
let s2_ok = bytestring_to_string_with_try(ok_bytestring.clone());
println!("s2_faulty: {:?}", s2_faulty);
println!("s2_ok: {:?}", s2_ok);
}use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};
// pub trait Error: Debug + Display + Reflect {
// fn description(&self) -> &str;
// fn cause(&self) -> Option<&Error> { None }
// }
#[derive(Debug)]
enum Currency {
USD,
EUR,
}
#[derive(Debug)]
struct CurrencyError {
description: String,
}
impl Display for CurrencyError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "CurrencyError: {}", self.description)
}
}
impl Error for CurrencyError {
fn description(&self) -> &str {
"Currency Error"
}
}
impl Currency {
fn new(currency: &str) -> Result<Self, CurrencyError> {
match currency {
"USD" => Ok(Currency::USD),
"EUR" => Ok(Currency::EUR),
e => Err(CurrencyError {
description: e.to_string(),
}),
}
}
}
#[derive(Debug)]
struct Money {
currency: Currency,
amount: u64,
}
#[derive(Debug)]
struct MoneyError {
cause: CurrencyError,
}
impl Display for MoneyError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "MoneyError due to {}", self.cause)
}
}
impl Error for MoneyError {
fn description(&self) -> &str {
"MoneyError"
}
fn cause(&self) -> Option<&Error> {
Some(&self.cause)
}
}
impl Money {
fn new(currency: &str, amount: u64) -> Result<Self, MoneyError> {
let currency = match Currency::new(currency) {
Ok(c) => c,
Err(err) => return Err(MoneyError { cause: err }),
};
Ok(Money {
currency: currency,
amount: amount,
})
// try!(Currency::new(currency))
}
}
fn main() {
let money_1 = Money::new("USD", 1000);
let money_2 = Money::new("MYR", 1000);
println!("money_1 is: {:?}", money_1);
println!("money_2 is: {:?}", money_2);
}
Output:
money_1 is: Ok(Money { currency: USD, amount: 1000 })
money_2 is: Err(MoneyError { cause: CurrencyError { description: "MYR" } })
// Interior mutability for Copy types
use std::cell::Cell;
fn main() {
// cannot borrow immutable local variable `x` as mutable
// let x = 1;
// let ref_to_x_1 = &mut x;
// let ref_to_x_2 = &mut x;
// *ref_to_x_1 += 1;
// *ref_to_x_2 += 1;
// println!("{} {} {}", x, ref_to_x_1, ref_to_x_2);
let x = Cell::new(1);
let ref_to_x_1 = &x;
let ref_to_x_2 = &x;
ref_to_x_1.set(ref_to_x_1.get() + 1);
println!("x: {:?}", x.get());
ref_to_x_2.set(ref_to_x_2.get() + 2);
println!(
"{:?} {:?} {:?}",
x.get(),
ref_to_x_1.get(),
ref_to_x_2.get()
);
x.set(0);
println!(
"{:?} {:?} {:?}",
x.get(),
ref_to_x_1.get(),
ref_to_x_2.get()
);
}// Interior mutability for Move types
use std::cell::RefCell;
#[derive(Debug)]
struct Foo {
number: u8,
}
fn main() {
let foo_one = RefCell::new(Foo { number: 1 });
let mut ref_to_foo_1 = foo_one.borrow_mut();
ref_to_foo_1.number = 10;
println!("foo_one: {:?}", foo_one);
drop(ref_to_foo_1); // There can be only one mutable reference
let mut ref_to_foo_2 = foo_one.borrow_mut();
println!("{:?}", ref_to_foo_2.number);
ref_to_foo_2.number = 20;
println!("{:?}", ref_to_foo_2.number);
drop(ref_to_foo_2);
let out = foo_one.borrow();
println!("foo_one: {:?}", out);
}Demonstrates that the cache is working without needing to make the whole p mutable.
use std::cell::Cell;
#[derive(Debug)]
struct Point {
x: u8,
y: u8,
cached_sum: Cell<Option<u8>>,
}
impl Point {
fn sum(&self) -> u8 {
match self.cached_sum.get() {
Some(sum) => {
println!("got from cache: {}", sum);
sum
}
None => {
let new_sum = self.x + self.y;
self.cached_sum.set(Some(new_sum));
println!("set cached: {}", new_sum);
new_sum
}
}
}
}
fn main() {
let p = Point {
x: 10,
y: 20,
cached_sum: Cell::new(None),
};
println!("Summed result: {}", p.sum());
println!("Summed result: {}", p.sum());
}
use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;
#[derive(Debug)]
struct LinkedList<T> {
head: Option<Rc<LinkedListNode<T>>>,
}
#[derive(Debug)]
struct LinkedListNode<T> {
next: Option<Rc<LinkedListNode<T>>>,
prev: RefCell<Option<Weak<LinkedListNode<T>>>>,
data: T,
}
impl<T> LinkedList<T> {
fn new() -> Self {
LinkedList { head: None }
}
fn append(&self, data: T) -> Self {
let new_node = Rc::new(LinkedListNode {
data: data,
next: self.head.clone(),
prev: RefCell::new(None),
});
match self.head.clone() {
Some(node) => {
let mut prev = node.prev.borrow_mut();
*prev = Some(Rc::downgrade(&new_node));
// node.prev = Some(Rc::downgrade(&new_node));
}
None => {}
}
LinkedList {
head: Some(new_node),
}
}
}
fn main() {
let list_of_nums = LinkedList::new().append(1).append(2);
println!("nums: {:?}", list_of_nums);
let list_of_strs = LinkedList::new().append("hello").append("world");
println!("strs: {:?}", list_of_strs);
}fn square(x: u32) -> u32 {
x * x
}
fn function_without_variables() {
println!("function without variables");
}
fn main() {
let square_1 = |x: u32| x * x;
let square_2 = |x: u32| { x * x };
let square_3 = |x: u32| -> u32 { x * x };
let closure_without_variables = || println!("closure without variables");
println!("square: {}", square(4));
println!("square_1: {}", square_1(4));
println!("square_2: {}", square_2(4));
println!("square_3: {}", square_3(4));
function_without_variables();
closure_without_variables();
}Output:
square: 16
square_1: 16
square_2: 16
square_3: 16
function without variables
closure without variables
fn main() {
let mut outer_scope = 42;
{
let mut closure = move || {
outer_scope += 42;
println!("value in closure: {}", outer_scope);
};
closure();
}
println!("value outside: {}", outer_scope);
}Output:
value in closure: 84
value outside: 42
use std::sync::Mutex;
use std::thread;
use std::sync::Arc;
use std::time;
const THREADS: u64 = 100_000;
const START_NUMBER: u64 = 1;
fn main() {
let one_millisecond = time::Duration::from_millis(1);
let one_second = time::Duration::from_secs(1);
let mutexed_number = Arc::new(Mutex::new(START_NUMBER));
let mutexed_number_2 = mutexed_number.clone();
thread::spawn(move || {
for _ in 1..THREADS {
let mutexed_number_clone = mutexed_number.clone();
thread::spawn(move || {
thread::sleep(one_millisecond);
let mut number = mutexed_number_clone.lock().unwrap();
*number += 1;
});
}
});
loop {
thread::sleep(one_second);
let number = mutexed_number_2.lock().unwrap();
if *number != THREADS {
println!("Not there yet. Number is {}", *number);
} else {
println!("Got there! Number is {}", *number);
break;
}
}
}Output:
Not there yet. Number is 33112
Not there yet. Number is 67477
Not there yet. Number is 99803
Got there! Number is 100000
[package]
name = "hypter-test"
version = "0.1.0"
authors = ["alextanhongpin <alextan@seekasia.com>"]
[dependencies]
reqwest = "0.8.5"
[[bin]]
name = "mybin"
path = "src/bin.rs"extern crate reqwest;
pub fn main() {
let body = reqwest::get("http://www.google.com").unwrap().text();
println!("body = {:?}", body);
}fn main() {
let res: Vec<i32> = (1..10).into_iter()
.map(|x| x * 2)
.filter(|x| x % 2 == 0)
.take(3)
.collect();
println!("{:?}", res);
}