RustStory_Data.html
copyright © James Fawcett
Revised: 07/30/2026
copyright © James Fawcett
Revised: 07/30/2026
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 enables the {:?} format specifier, which uses a standard formatting process for each Rust type. -
Copy causes the compiler to copy an instance's value by blitting (memcpy) to the new location. The compiler refuses to derive Copy if any member is non-blittable or the type already implements Drop. -
Clone is not called implicitly. A designer can call clone() explicitly, paying whatever performance penalty the copy requires. Implementing Copy also requires implementing 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<i32>, populate it with 5 arbitrary elements, and display the value and address of each element. This reference may help. No unsafe block is required. -
Create a std::collections::HashMap and populate it with information about projects you are working on. Use the project name as the key; provide purpose, programming language, and status as associated items. Display the results on the console. -
Create an array of Strings with arbitrary values and convert it to a Vec. -
Construct a str instance and convert it to a String. Evaluate the addresses of the str, the String, and the first element of the String. Convert the String back to another str. Display everything you built and evaluated. -
Declare a struct with fields describing your current employment and display it on the console. -
Repeat the last exercise using 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. |
url
url
Sections