about
RustStory Data
6/8/2022
Chapter 2. - Rust Data
Types, type deduction, ownership
2.0 Prologue
Example:
Example:
References are borrows
/* attempt to mutate after borrow */
let mut s = String::from("s is owner");
slog(&s);
{
let rs = &s; // borrow s
// statement below fails to compile
// owner can't mutate after borrow
// s += " with stuff";
slog(&rs);
} // borrow ends here
s += " with stuff";
slog(&s);
2.1 Data and its Life Cycle
-
Blittable types:
Stored entirely in one contiguous block of stack memory.
-
Basic Types:
u8, i8, u16, i16, u32, i32, u64, i64, usize, isize, f32, f64, bool, char, str -
Aggregate Types:
array, tuple, struct if all their items are blittable - User-Defined Types that have all blittable members and are marked Copy with #[derive(Copy)]
-
Basic Types:
-
Non-Blittable types:
Control block stored in one contiguous block of stack memory with references to data held in the heap.
-
Std Library Types:
String, Box, Vec, VecDeque, LinkedList, HashMap, HashSet, BTreeMap, BTreeSet, BinaryHeap -
Aggregate Types:
array, tuple, struct if each has at least one non-blittable member - User-defined types that have at least one non-blittable member
-
Std Library Types:
2.2 Rust Types and Type Deduction
Type Deduction
Fully qualified vs. deduced types
Output
use std::fmt::{Debug};
#[allow(dead_code)]
pub fn run () {
/*-- fully specified --*/
let i:i32 = 5;
let f:f64 = 3.4;
let a:[f32; 5] = [1.0, 1.5, 2.0, 1.5, 1.0];
let t:(i32, f64, String) = (1, 2.0, "three".to_string());
#[derive(Debug)]
struct S{i:i32, s:&'static str, };
let s:S = S{i:15, s:"a literal string" };
#[derive(Debug)]
enum E {BS(String), MS(String), PhD(String),};
let e:E = E::MS("Computer Engineering".to_string());
print!("\n -- fully specified types --\n");
print!("\n i = {:?}", i);
print!("\n f = {:?}", f);
print!("\n a = {:?}", a);
print!("\n t = {:?}", t);
print!("\n s = {:?}", s);
print!("\n e = {:?}", e);
/*-- using type deduction --*/
let i = 5;
let f = 3.4;
let a = [1.0, 1.5, 2.0, 1.5, 1.0];
let t = (1, 2.0, "three".to_string());
let s = S{i:15, s:"a literal string" };
let e = E::MS("Computer Engineering".to_string());
print!("\n\n -- using type deduction --\n");
print!("\n i = {:?}", i);
print!("\n f = {:?}", f);
print!("\n a = {:?}", a);
print!("\n t = {:?}", t);
print!("\n s = {:?}", s);
print!("\n e = {:?}", e);
}
C:\github\JimFawcett\RustBasicDemos\rust_probes>
cargo -q run
-- fully specified types --
i = 5
f = 3.4
a = [1.0, 1.5, 2.0, 1.5, 1.0]
t = (1, 2.0, "three")
s = S { i: 15, s: "a literal string" }
e = MS("Computer Engineering")
-- using type deduction --
i = 5
f = 3.4
a = [1.0, 1.5, 2.0, 1.5, 1.0]
t = (1, 2.0, "three")
s = S { i: 15, s: "a literal string" }
e = MS("Computer Engineering")
2.2.1 Basic Data Types
Basic Types
Basic Types code from main
Output
title("exploring basic types".to_string());
/*
Rust basic types:
i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize
f32, f64, char, bool, ()
*/
let demo :i8 = 3;
putln(&"let demo :i8 = 3;");
log(&demo);
separator();
let demo = 5;
putln(&"let demo = 5;");
log(&demo);
separator();
let demo :usize = 7;
putln(&"let demo :usize = 7;");
log(&demo);
/* Rust floats: f32, f64 */
separator();
let demo = 3.5;
putln(&"let demo = 3.5;");
log(&demo);
separator();
let demo :f32 = -3.5;
putln(&"let demo :f32 = -3.5;");
log(&demo);
/* Rust chars: char */
separator();
let demo = 'a';
putln(&"let demo = 'a';");
log(&demo);
separator();
let demo :char = 'Z';
putln(&"let demo :char = 'Z';");
log(&demo);
/* Rust boolean: bool */
separator();
let demo = true;
putln(&"let demo = true;");
log(&demo);
separator();
let demo :bool = false;
putln(&"let demo :bool = false");
log(&demo);
/* Rust unit type: () */
separator();
let demo = ();
putln(&"let demo = ();");
log(&demo);
separator();
let demo :() = ();
putln(&"let demo :() = ();");
log(&demo);
C:\github\JimFawcett\RustBasicDemos\data_types>
cargo -q run
exploring basic types
-----------------------
let demo :i8 = 3;
TypeId: i8, size: 1
value: 3
---------------------------------
let demo = 5;
TypeId: i32, size: 4
value: 5
---------------------------------
let demo :usize = 7;
TypeId: usize, size: 4
value: 7
---------------------------------
let demo = 3.5;
TypeId: f64, size: 8
value: 3.5
---------------------------------
let demo :f32 = -3.5;
TypeId: f32, size: 4
value: -3.5
---------------------------------
let demo = 'a';
TypeId: char, size: 4
value: 'a'
---------------------------------
let demo :char = 'Z';
TypeId: char, size: 4
value: 'Z'
---------------------------------
let demo = true;
TypeId: bool, size: 1
value: true
---------------------------------
let demo :bool = false
TypeId: bool, size: 1
value: false
---------------------------------
let demo = ();
TypeId: (), size: 0
value: ()
---------------------------------
let demo :() = ();
TypeId: (), size: 0
value: ()
main.rs
#[allow(unused_imports)]
use display::{ putline, title, show_type, log, putlinen };
use std::fmt::{ Debug, Display };
#[allow(dead_code)]
fn put<T: Display>(value: &T) {
print!("{}", value);
}
fn putln<T: Display>(value: &T) {
let mut str_temp = String::new();
str_temp.push_str("\n ");
str_temp.push_str(&value.to_string());
print!("{}", str_temp);
}
fn separator() {
put(&"\n ---------------------------------");
}
fn main() {
/* code elided - see panel above */
}
2.2.2 Aggregate Data Types
Aggregate Types
Aggregates Demonstration Code
Output
/*-- create and display basic aggregates -*/
fn basic_aggr() {
show_title("Demonstrate Rust Aggregates");
/*-- array --*/
show_label("arrays");
show_op("let mut arr:[i32; 5] = [1, 2, 3, 4, 5]");
let mut arr: [i32; 5] = [1, 2, 3, 4, 5];
show_type(&arr);
show_value(&arr);
show_op("arr[1] = -2");
arr[1] = -2;
show_value(&arr);
println!();
/*-- slice --*/
show_label("slices");
show_op("let slc = &mut arr[1..4]");
let slc = &mut arr[1..4];
show_type(&slc);
show_value(&slc);
show_op("slc[0] = 0");
slc[0] = 0;
show_value(&slc);
show_op("value of array is now:");
show_value(&arr);
println!();
/*-- tuple --*/
show_label("tuples");
show_op("let tpl = (42, 'z', \"abc\", 3.14159)");
#[allow(clippy::approx_constant)]
let tpl = (42, 'z', "abc", 3.14159);
show_type(&tpl);
show_value(&tpl);
show_op("value of second element is:");
show_value(&tpl.1);
println!();
/*-- string --*/
show_label("strings");
show_op("let s = \"a string\".to_string()");
let mut s = "a string".to_string();
show_type(&s);
show_value(&s);
show_op("s.push_str(\" plus more\")");
s.push_str(" plus more");
show_value(&s);
println!();
/*-- reference --*/
show_label("references");
show_op("let r = &s");
let r = &s;
show_type(&r);
show_value(&r);
println!();
/*-- struct --*/
show_label("structures");
#[derive(Debug)]
struct DemStr { i:i32, c:char, d:f64, }
show_op("let st = DemStr { i:1, c:'a', d:0.333 }");
let st = DemStr { i:1, c:'a', d:0.333 };
show_type(&st);
show_value(&st);
let second = st.c;
show_op("let second = st.c");
show_value(&second);
println!();
/*-- enum --*/
show_label("enumerations");
#[derive(Debug)]
enum LangAge { Recent, Ancient }
#[derive(Debug)]
enum Langs {
Rust(LangAge), Fortran(LangAge)
}
let a_lang = Langs::Rust(LangAge::Recent);
show_type(&a_lang);
show_value(&a_lang);
let old_lang = Langs::Fortran(LangAge::Ancient);
show_type(&old_lang);
show_value(&old_lang);
/*-- matching requires handling all branches --*/
match a_lang {
Langs::Rust(LangAge::Recent) => { println!(" Rust is recent"); }
Langs::Rust(LangAge::Ancient) => { println!(" Rust is ancient"); }
Langs::Fortran(LangAge::Recent) => { println!(" Fortran is recent"); }
Langs::Fortran(LangAge::Ancient) => { println!(" Fortran is ancient"); }
}
/*-------------------------------------------------------
if let can examine one branch and provide
blanket handling for others
*/
if let Langs::Rust(LangAge::Recent) = a_lang {
println!(" Rust was stablized in 2015")
} else {
println!(" this language isn't very interesting");
}
}
fn move_copy() {
show_title("Demonstrate Copy and Move");
show_label("copy array of integers");
show_op("let arri = [ 1, 2, 3, 2, 1]");
let arri = [ 1, 2, 3, 2, 1];
show_value(&arri);
show_op("let carri = arri");
let carri = arri;
show_value(&carri);
// the next statement succeeds because arri was copied
// println!("{arri:?}");
println!();
show_label("copy array of &strs");
show_op("let arri = [ \"1\", \"2\", \"3\", \"2\", \"1\"]");
let arri = [ "1", "2", "3", "2", "1"];
show_value(&arri);
show_op("let carri = arri");
let carri = arri;
show_value(&carri);
// the next statement succeeds because arri was copied
// println!("{arri:?}");
println!();
show_label("move array of Strings");
show_op(
"let arri = [\"1\".to_owned(), \"2\".to_owned(),
\"3\".to_owned(), \"2\".to_owned(), \"1\".to_owned()])"
);
/*------------------------------------------------------
to_owned() converts copy type &str
to move type String
*/
let arri = [
"1".to_owned(), "2".to_owned(), "3".to_owned(),
"2".to_owned(), "1".to_owned()
];
show_value(&arri);
show_op("let carri = arri");
let carri = arri;
show_value(&carri);
// the next statement fails because arri was moved
// println!("{arri:?}");
println!(" arri moved so no longer valid\n");
println!(" an aggregate of all copy types is copy");
println!(" an aggregate with at least one move type element is move");
}
-----------------------------
Demonstrate Rust Aggregates
-----------------------------
arrays
--------
--- let mut arr:[i32; 5] = [1, 2, 3, 4, 5] ---
TypeId: [i32; 5], size: 20
value: [1, 2, 3, 4, 5]
--- arr[1] = -2 ---
value: [1, -2, 3, 4, 5]
slices
--------
--- let slc = &mut arr[1..4] ---
TypeId: &mut [i32], size: 16
value: [-2, 3, 4]
--- slc[0] = 0 ---
value: [0, 3, 4]
--- value of array is now: ---
value: [1, 0, 3, 4, 5]
tuples
--------
--- let tpl = (42, 'z', "abc", 3.14159) ---
TypeId: (i32, char, &str, f64), size: 32
value: (42, 'z', "abc", 3.14159)
--- value of second element is: ---
value: 'z'
strings
---------
--- let s = "a string".to_string() ---
TypeId: alloc::string::String, size: 24
value: "a string"
--- s.push_str(" plus more") ---
value: "a string plus more"
references
------------
--- let r = &s ---
TypeId: &alloc::string::String, size: 8
value: "a string plus more"
structures
------------
--- let st = DemStr { i:1, c:'a', d:0.333 } ---
TypeId: aggr_probes::basic_aggr::DemStr, size: 16
value: DemStr { i: 1, c: 'a', d: 0.333 }
--- let second = st.c ---
value: 'a'
enumerations
--------------
TypeId: aggr_probes::basic_aggr::Langs, size: 2
value: Rust(Recent)
TypeId: aggr_probes::basic_aggr::Langs, size: 2
value: Fortran(Ancient)
Rust is recent
Rust was stablized in 2015
---------------------------
Demonstrate Copy and Move
---------------------------
copy array of integers
------------------------
--- let arri = [ 1, 2, 3, 2, 1] ---
value: [1, 2, 3, 2, 1]
--- let carri = arri ---
value: [1, 2, 3, 2, 1]
copy array of &strs
---------------------
--- let arri = [ "1", "2", "3", "2", "1"] ---
value: ["1", "2", "3", "2", "1"]
--- let carri = arri ---
value: ["1", "2", "3", "2", "1"]
move array of Strings
-----------------------
--- let arri = ["1".to_owned(), "2".to_owned(),
"3".to_owned(), "2".to_owned(), "1".to_owned()]) ---
value: ["1", "2", "3", "2", "1"]
--- let carri = arri ---
value: ["1", "2", "3", "2", "1"]
arri moved so no longer valid
an aggregate of all copy types is copy
an aggregate with at least one move type element is move
- Debug allows you to use {:?} in a format which uses a standard formatting process for each of the Rust types.
- Copy causes the compiler to copy an instance's value by blitting (memcpy) to the new location. The compiler will refuse to derive Copy if any member is non-blittable or the type already implements the Drop trait.
- Clone is not called implicitly, but a designer can write code that calls clone() and then pays whatever performance penalty accrues for making the copy. If you implement Copy you are also required to implement Clone.
2.2.3 Slices of Aggregate Types:
-
let slc1 = &arr[..]; // view the entire array -
let slc2 = &arr[0..6]; // same as slc1 -
let slc3 = &arr[..3]; // views elements [1, 2, 3] -
let slc4 = &arr[1..]; // views elements [2, 3, 4, 5, 6] -
let slc5 = &arr[1..4]; // views elements [2, 3, 4]
2.2.4 String Types:
2.2.4.1 String
2.2.4.2 str
-
let s = String::from("a literal string"); -
let s = "a literal string".to_string();
-
let s1 = "Hello world"; // slice of the whole literal -
let s2 = &s[1..3]; // second through 4th bytes of s
2.2.5 String Examples:
-
let s = String::new();
Creates new empty String instance -
let s = String::from("a literal");
Creates instance from literal -
let t = s.replace("abc","xyz");
t is a copy ofs with every instance of"abc" replaced with"xyz" -
s.len();
returns length ofs in bytes, not chars -
let slice = s.as_str();
returns slice of entire Strings contents -
s.push('a');
append char'a' to end ofs . -
s.push_str("abc");
appends"abc" to the end ofs -
let st = s.trim();
returns string with leading and trailing whitespace removed. -
let iter = s.split_whitespace();
returns iterator over whitespace separated tokens -
let iter = s.split('\n');
returns iterator over lines -
let iter = s.chars();
returns an iterator over the utf-8 chars ofs
String Examples:
String Demonstration Code
Output
fn main() {
main_title("string_probes");
putlinen(2);
/*-- char --*/
show_op("let v = vec!['R', 'u', 's', 't']");
let v:Vec<char> = vec!['R', 'u', 's', 't'];
log(&v);
log(&'R');
putlinen(2);
show_op("let ch = 'a' as u8");
let ch:u8 = 'a' as u8;
log(&ch);
show("char is ", &(ch as char));
putlinen(2);
/*-- String --*/
show_op("let s = String::from(\"Rust\")");
let s:String = String::from("Rust");
log(&s);
let i:usize = 2;
let ch = at(&s, i);
print!("\n in string \"{}\", char at {} is {}", &s, i, ch);
show("length in bytes of s = {:?}", &s.len());
putlinen(2);
show_op("let v = Vec::from(s.clone())");
let s1 = s.clone();
let v:Vec<u8> = Vec::from(s1);
log(&v[0]);
show("vec from string",&v);
putlinen(2);
/*-----------------------------------------------------
Displaying emoji's to illustrate the potential
of using utf-8.
*/
show_op("displaying emoji's");
let mut s2 = String::new();
s2.push_str("\u{1F600}");
s2.push('\u{1F601}');
s2.push('\u{1F602}');
s2.push('\u{1F609}');
print!("\n {}", s2);
print!("\n {}", '\u{1F601}');
putlinen(2);
/*-- str --*/
show_op("let s_slice = &s[..]");
let s_slice = &s[..]; // slice containing all chars of s
log(&s_slice);
show("s_slice = ", &s_slice);
putlinen(2);
show_op("let s_slice2 = s.as_str()");
let s_slice2 = s.as_str();
log(&s_slice2);
putlinen(2);
/*-- create string and mutate --*/
show_op("let mut s = string::new()");
let mut s = String::new();
s.push('a');
s.push(' ');
s.push_str("test string");
log(&s);
putlinen(2);
show_op("let t = s.replace(from: \"string\", to: \"Rust String\"");
let t = s.replace("string","Rust String");
log(&t);
putlinen(2);
show_op("tok in s.split_whitespace()");
for tok in s.split_whitespace() {
print!("\n {}", tok);
}
putline();
/*-----------------------------------------------------
Another, order n, way to index string:
- chars returns iterator over utf8 chars in string slice
- nth(i) calls next on iterator until it gets to i
- nth(i) returns std::option::Option<char>:
- that contains Some(ch) or None if operation failed
*/
show("\n s = ", &s);
putline();
show_op("let result = s.chars().nth(0)");
putline();
let result = s.chars().nth(0);
match result {
Some(r) => show(" s.chars().nth(0) = ", &r),
None => print!("\n couldn't extract char"),
}
putline();
show_op("let result = s.chars().nth(2)");
putline();
let result = s.chars().nth(2);
match result {
Some(r) => show(" s.chars().nth(2) = ", &r),
None => print!("\n couldn't extract char"),
}
putlinen(2);
{
/*-------------------------------------------------
Caution here:
- slice is returning array of bytes, not utf8 chars
- this works only because we use all ASCII chars
*/
/*-- slices are non-owning views and are borrows of s --*/
show_op("let slice_all = &s");
let slice_all = &s;
log(&slice_all);
show("slice_all = ", &slice_all);
putlinen(2);
show_op("let third = &s[2..3]");
let third = &s[2..3]; // string slice with one char
log(&third);
show("\n third = ",&third);
putlinen(2);
/*-- this works for utf-8 encoding --*/
show_op("let ch = third.chars().nth(0)");
let ch = third.chars().nth(0); //
log(&ch);
match ch {
Some(x) => { log(&x); show("\n match ch = ", &x); },
None => print!("\n can't return ch"),
}
///////////////////////////////////////////////////
// compile fails
// - can't modify owner while borrows are active
//------------------------------------------------
// s.push('Z');
// log(&slice_all);
} // elem borrow ends here
s.push('Z'); // ok, borrows no longer active
putlinen(2);
/* format_args! macro */
show_op("let s = std::fmt::format(format_args!(...))");
let s = std::fmt::format(format_args!("\n {}, {}, {}", 1, 2, 3.5));
put_str(&s);
put(&s);
putlinen(2);
show_op("struct S { x:i32, y:f64, s:String, }");
#[allow(dead_code)]
#[derive(Debug)]
struct S {x:i32, y:f64, s:String, }
let st:S = S { x:3, y:4.2, s:"xyz".to_string() };
put("\n ");
putdb(&st);
putline();
sub_title("That's all Folks!");
putlinen(2);
}
string_probes
===============
--- let v = vec!['R', 'u', 's', 't'] ---
TypeId: alloc::vec::Vec, size: 24
value: ['R', 'u', 's', 't']
TypeId: char, size: 4
value: 'R'
--- let ch = 'a' as u8 ---
TypeId: u8, size: 1
value: 97char is 'a'
--- let s = String::from("Rust") ---
TypeId: alloc::string::String, size: 24
value: "Rust"
in string "Rust", char at 2 is slength in bytes of s = {:?}4
--- let v = Vec::from(s.clone()) ---
TypeId: u8, size: 1
value: 82vec from string[82, 117, 115, 116]
--- displaying emoji's ---
😀😁😂😉
😁
--- let s_slice = &s[..] ---
TypeId: &str, size: 16
value: "Rust"s_slice = "Rust"
--- let s_slice2 = s.as_str() ---
TypeId: &str, size: 16
value: "Rust"
--- let mut s = string::new() ---
TypeId: alloc::string::String, size: 24
value: "a test string"
--- let t = s.replace(from: "string", to: "Rust String" ---
TypeId: alloc::string::String, size: 24
value: "a test Rust String"
--- tok in s.split_whitespace() ---
a
test
string
s = "a test string"
--- let result = s.chars().nth(0) ---
s.chars().nth(0) = 'a'
--- let result = s.chars().nth(2) ---
s.chars().nth(2) = 't'
--- let slice_all = &s ---
TypeId: &alloc::string::String, size: 8
value: "a test string"slice_all = "a test string"
--- let third = &s[2..3] ---
TypeId: &str, size: 16
value: "t"
third = "t"
--- let ch = third.chars().nth(0) ---
TypeId: core::option::Option, size: 4
value: Some('t')
TypeId: char, size: 4
value: 't'
match ch = 't'
--- let s = std::fmt::format(format_args!(...)) ---
1, 2, 3.5
1, 2, 3.5
--- struct S { x:i32, y:f64, s:String, } ---
S { x: 3, y: 4.2, s: "xyz" }
That's all Folks!
-------------------
Functions defined above main()
/////////////////////////////////////////////////////////////
// string_probes::main.rs - basic string operations //
// //
// Jim Fawcett, https://JimFawcett.github.io, 25 Feb 2020 //
/////////////////////////////////////////////////////////////
#[allow(unused_imports)]
use display::{
log, slog, show, show_type, show_value,
putline, putlinen, main_title, sub_title
};
#[allow(unused_imports)]
use std::fmt::{ Debug, Display };
fn show_op(s:&str) {
let strg = "--- ".to_owned() + s + " ---";
print!("{}", strg);
}
fn put<T>(t:T) where T:Display {
print!("{}", t);
}
fn putdb<T>(t:T) where T:Debug {
print!("{:?}", t);
}
fn put_str(s:&String) {
print!("{}",s);
}
/*-----------------------------------------------------------
Note:
Strings hold utf8 characters, which vary in size, so you
you can't directly index String instances.
*/
#[allow(dead_code)]
pub fn at(s:&String, i:usize) -> char {
s.chars().nth(i).unwrap()
}
/*-----------------------------------------------------------
note:
- order n, as str chars are utf8, e.g., from 1 to 5 bytes
- this ugliness is one way to index
- see below for another, not much better way
*/
#[allow(dead_code)]
pub fn vectorize(s: &str) -> Vec<char> {
s.chars().collect::<Vec<char>>()
}
/*-- note: order n, from vectorize -- prefer at, above --*/
#[allow(dead_code)]
pub fn get_char(s:&str, i:usize) -> char {
vectorize(s)[i]
}
/*-- stringize - order n --*/
#[allow(dead_code)]
pub fn stringize(v: &Vec<char>) -> String {
return v.into_iter().collect()
}
2.3 Structs
-
StructExprStruct:
struct Person { name:String, occupation:String, age:u32, }
-
StructExprTuple:
struct Person ( String, String, u32, )
-
StructExprUnit:
struct Person;
Define Structs
Use Structs
#[allow(unused_imports)]
use display::{*};
use std::fmt;
/*-- ExprStruct struct --*/
#[derive(Debug)]
struct Person1 {
name:String, occup:String, id:u32,
}
#[allow(dead_code)]
impl Person1 {
fn show(&self) {
print!("\n Person1: {:?}", &self);
}
}
/*-- ExprTuple struct --*/
#[derive(Debug)]
struct Person2 (
String, String, u32
);
#[allow(dead_code)]
impl Person2 {
fn show(&self) {
print!("\n Person2: {:?}", &self);
}
}
/*-- ExprUnit struct --*/
#[derive(Debug)]
struct Person3;
#[allow(dead_code)]
impl Person3 {
fn show(&self) {
print!("\n Person3");
}
}
sub_title("Demonstrating Basic Structs");
let p1 = Person1 {
name:"Jim".to_string(),
occup:"dev".to_string(),
id:42
};
p1.show();
let p2 = Person2 {
0:"Jim".to_string(),
1:"dev".to_string(),
2:42
};
p2.show();
let p3 = Person3;
p3.show();
putline();
Output
Demonstrating Basic Structs
-----------------------------
Person1: Person1 { name: "Jim", occup: "dev", id: 42 }
Person2: Person2("Jim", "dev", 42)
Person3
2.4 Enumerations
-
ItemDiscriminant : a named integral valueenum Names { John, Sally = 35, Roger }; -
ItemTuple : a named tuple with items specified by typeenum Names { Alok(String, f64), Priya(String, f64), Ram(String, f64) }; -
ItemStruct : a named struct with items specified by name and typeenum Names { Jun { occupation: String, age: f64 }, Xing { occupation: String, age: f64 }, Shi { occupation: String, age: f64 }, }
Enumeration Examples
Enumeration Example Code
Output
// enum_probes::main.rs
use display::{*};
use std::fmt::{Debug};
#[allow(dead_code)]
#[derive(Debug)]
enum Name { John, Jim=42, Jack }
#[allow(dead_code)]
#[derive(Debug)]
enum NameTuple {
John(String, u32), Jim(String, u32), Jack(String, u32)
}
#[allow(dead_code)]
#[derive(Debug)]
enum NameStruct {
John { occup:String, id:u32 },
Jim { occup:String, id:u32 },
Jack { occup:String, id:u32 }
}
fn main() {
main_title("Demonstrating enum_probes");
print!("\n - enumerations, match, if let");
putline();
/*-- enum discriminant --*/
sub_title(" -- enum discriminant -- ");
let test = Name::Jim;
match test {
Name::John => {
let john_discriminant = Name::John as u32;
print!(
"\n I am John. my discriminant is {:?}",
john_discriminant
)},
Name::Jim => {
let jim_discriminant = Name::Jim as u32;
print!(
"\n I am Jim. my discriminant is {:?}",
jim_discriminant
)},
Name::Jack => {
let jack_discriminant = Name::Jack as u32;
print!(
"\n I am Jack. my discriminant is {:?}",
jack_discriminant
)},
}
putline();
let test1 = Name::John;
let test2 = Name::Jim;
let test3 = Name::Jack;
if let Name::Jack = test1 {
print!("\n I am John");
}
else {
print!("\n I am not John");
}
if let Name::Jack = test2 {
print!("\n I am Jim");
}
else {
print!("\n I am not Jim");
}
if let Name::Jack = test3 {
print!("\n I am Jack");
}
else {
print!("\n I am not Jack");
}
putline();
/*-- enum tuple --*/
sub_title(" -- enum tuple -- ");
let value = NameTuple::John("pilot".to_string(), 52);
if let NameTuple::John(occup, id) = value {
print!(
"
my name is John
occupupation is {}
id is {}", occup, id
);
}
putline();
/*-- enum struct --*/
sub_title(" -- enum struct -- ");
let value = NameStruct::Jack { occup:"plumber".to_string(), id:32 };
match value {
NameStruct::Jack {occup, id} => print!("\n Jack - occup: {}, id: {}", occup, id),
_ => print!("\n not Jack")
}
putline();
println!("\n\nThat's all Folks!\n");
}
Demonstrating enum_probes
===========================
- enumerations, match, if let
-- enum discriminant --
-----------------------------
I am Jim. my discriminant is 42
I am not John
I am not Jim
I am Jack
-- enum tuple --
----------------------
my name is John
occupupation is pilot
id is 52
-- enum struct --
-----------------------
Jack - occup: plumber, id: 32
That's all Folks!
2.5 Type Aliases
-
type PointF = (f64, f64, f64); // tuple of three doubles -
type VecPoint = Vec<PointF>
2.6 Std Lib Data Types
StdLib Data Types
stdlib Examples
Output
fn main() {
show_title("Demonstrate std Library Types");
use std::collections::{VecDeque, HashMap};
show_label("std::Vec<T>");
show_op("let mut vi = vec![1, 2, 3, 2, 1]");
let mut vi = vec![1, 2, 3, 2, 1];
show_type(&vi);
show_value(&vi);
show_op("vi[1] = -2");
vi[1] = -2;
show_value(&vi);
show_op("vi.push(0)");
vi.push(0);
show_value(&vi);
show_op("vi.insert(1, 42)");
vi.insert(1, 42);
show_value(&vi);
println!();
show_label("VecDeque<T>");
show_op("let mut vdeq = VecDeque::<f64>::new()");
let mut vdeq = VecDeque::<f64>::new();
show_type(&vdeq);
show_value(&vdeq);
show_op("vdeq.push_back(2.5)");
vdeq.push_back(2.5);
show_op("vdeq.push_front(1.0)");
vdeq.push_front(1.0);
show_value(&vdeq);
println!();
show_label("HashMap<K, V>");
show_op("let mut hm = HashMap::<i32, &str>::new()");
let mut hm = HashMap::<i32, &str>::new();
show_type(&hm);
show_value(&hm);
show_op("hm.insert(1,\"one\")");
hm.insert(1,"one");
show_value(&hm);
hm.insert(0,"zero");
show_value(&hm);
hm.insert(2,"two");
show_value(&hm);
hm.insert(-2,"minus two");
show_value(&hm);
show_op("hm.remove(&0)");
hm.remove(&0);
show_value(&hm);
/*
using entry API for HashMap
- if the key exists then modify the value
with a closure
*/
show_op("hm.entry(1).and_modify(|v| *v = \"the number 1\")");
hm.entry(1).and_modify(|v| *v = "the number 1");
show_value(&hm);
println!("\n That's all Folks!");
}
-------------------------------
Demonstrate std Library Types
-------------------------------
std::Vec<T>
-------------
--- let mut vi = vec![1, 2, 3, 2, 1] ---
TypeId: alloc::vec::Vec, size: 24
value: [1, 2, 3, 2, 1]
--- vi[1] = -2 ---
value: [1, -2, 3, 2, 1]
--- vi.push(0) ---
value: [1, -2, 3, 2, 1, 0]
--- vi.insert(1, 42) ---
value: [1, 42, -2, 3, 2, 1, 0]
VecDeque<T>
-------------
--- let mut vdeq = VecDeque::::new() ---
TypeId: alloc::collections::vec_deque::VecDeque, size: 32
value: []
--- vdeq.push_back(2.5) ---
--- vdeq.push_front(1.0) ---
value: [1.0, 2.5]
HashMap
---------------
--- let mut hm = HashMap::::new() ---
TypeId: std::collections::hash::map::HashMap, size: 48
value: {}
--- hm.insert(1,"one") ---
value: {1: "one"}
value: {1: "one", 0: "zero"}
value: {1: "one", 2: "two", 0: "zero"}
value: {-2: "minus two", 1: "one", 2: "two", 0: "zero"}
--- hm.remove(&0) ---
value: {-2: "minus two", 1: "one", 2: "two"}
--- hm.entry(1).and_modify(|v| *v = "the number 1") ---
value: {-2: "minus two", 1: "the number 1", 2: "two"}
That's all Folks!
2.7 Epilogue:
2.7.1 Exercises:
- Construct a vec of i32 elements, populate it with 5 arbitrary elements, then display the value and address of each element. This reference may help. Note that you don't need an unsafe block for this exercise.
- Create an instance of std::collections::HashMap. Populate it with information about projects on which you are working. Use project name as the key, and provide a small collection of items about the project, i.e., purpose, programming language, and status. Display the results on the console.
- Create an array of Strings, populating with arbitrary values. Convert the array to a Vec.
- Construct a str instance and convert it to a String. Evaluate the address of the str, the String, and the first element of the String. Now, convert the String back to another str. Display everything you have built and evaluated.
- Declare a struct that has fields to describe your current employment. Display that on the console.
- Repeat the last exercise, but use a tuple. Use type aliases to make the tuple understandable.
2.7.2 References:
Reference Link | Description |
---|---|
Character sets | The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Escuses!) [author's title] - Joel Spolsky |
utf-8 Strings - amos | Illustrating how utf-8 strings work with C and with Rust code. |
Rust Strings | Rust Strings are implemented with Vec<u8> but interpreted as utf-8 chars |
regex Crate | Rust regex crate provides facilities for parsing, compiling, and executing regular expressions. |
Rust Lifetimes | Very clear presentation of borrow lifetimes. |
Rust Reference: Structs | Rust Reference is the official language definition - surprisingly readable. |
Rust Containers | Container diagrams |
rust-lang.org home page | Links to download and documentation |
Tutorial - tutorialspoint.com | Tutorials for most of the Rust parts with code examples. |