Long ago, when shepherds wanted to see if two herds of sheep were isomorphic, they would look for an explicit isomorphism. —John C. Baez and James Dolan, “
Named-Field Structs
// A rectangle of eight-bit grayscale pixels.
struct GrayscaleMap {
pixels: Vec<u8>,
size: (usize, usize)
}
let width = 1024;
let height = 576;
let image = GrayscaleMap {
pixels: vec![0; width * height],
size: (width, height)
};
image
[E0277] Error: `GrayscaleMap` doesn't implement `Debug`
/// A rectangle of eight-bit grayscale pixels.
// 模块外访问
pub struct GrayscaleMap {
pub pixels: Vec<u8>,
pub size: (usize, usize)
}
Tuple-Like Structs
#[derive(Copy, Clone, Debug)]
struct Bounds(usize, usize);
let image_bounds = Bounds(1024, 768);
image_bounds
The type of the variable image was redefined, so was lost.
Bounds(1024, 768)
Unit-Like Structs
struct A;
let a=A;
Struct Layout 内存布局
Defining Methods with impl
/// A first-in, first-out queue of characters.
pub struct Queue {
older: Vec<char>, // older elements, eldest last.
younger: Vec<char> // younger elements, youngest last.
}
impl Queue {
pub fn push(&mut self,c: char) {
self.younger.push(c);
}
pub fn pop(&mut self) -> Option<char> {
if self.older.is_empty() {
if self.younger.is_empty() {
return None;
}
use std::mem::swap;
swap(&mut self.older,&mut self.younger);
self.older.reverse();
}
self.older.pop()
}
}
let mut q = Queue { older: Vec::new(), younger: Vec::new() };
q.push('0');
q.push('1');
assert_eq!(q.pop(), Some('0'));
q.push('∞');
assert_eq!(q.pop(), Some('1'));
assert_eq!(q.pop(), Some('∞'));
assert_eq!(q.pop(), None);
impl Queue {
pub fn is_empty(&self) -> bool {
self.older.is_empty() && self.younger.is_empty()
}
}
assert!(q.is_empty());
q.push('☉');
assert!(!q.is_empty());
impl Queue {
pub fn split(self) -> (Vec<char>, Vec<char>) {
(self.older, self.younger)
}
}
let mut q = Queue { older: Vec::new(), younger: Vec::new() };
q.push('P');
q.push('D');
assert_eq!(q.pop(), Some('P'));
q.push('X');
let (older, younger) = q.split();
// q is now uninitialized.
assert_eq!(older, vec!['D']);
assert_eq!(younger, vec!['X'])
()
q
[E0425] Error: cannot find value `q` in this scope
╭─[command_23:1:1]
│
1 │ q
│ ┬
│ ╰── error: cannot find value `q` in this scope
│ │
│ ╰── help: a unit struct with a similar name exists: `A`
───╯
impl Queue {
fn new() -> Queue {
Queue { older: Vec::new(), younger: Vec::new() }
}
}
let mut bq = Box::new(Queue::new());
bq.push('A')
()
use std::rc::Rc;
struct Node {
tag: String,
children: Vec<Rc<Node>>
}
impl Node {
fn new(tag: &str) ->Node {
Node {
tag: tag.to_string(),
children: vec![],
}
}
}
impl Node {
fn append_to(self: Rc<Self>, parent: &mut Node) {
parent.children.push(self);
}
}
let shared_node = Rc::new(Node::new("first"));
pub struct Vector2 {
x: f32,
y: f32,
}
impl Vector2 {
const ZERO: Vector2 = Vector2 { x: 0.0, y: 0.0 };
const UNIT: Vector2 = Vector2 { x: 1.0, y: 0.0 };
}
let scaled = Vector2::UNIT.x;
Generic Structs
pub struct TheQueue<T> {
older: Vec<T>,
younger: Vec<T>
}
impl<T> TheQueue<T> {
pub fn new() -> TheQueue<T> {
TheQueue { older: Vec::new(), younger: Vec::new() }
}
pub fn push(&mut self, t: T) {
self.younger.push(t);
}
pub fn is_empty(&self) -> bool {
self.older.is_empty() && self.younger.is_empty()
}
}
impl TheQueue<f64> {
fn sum(&self) -> f64 {
0_f64
}
}
let mut q = TheQueue::<char>::new();
q.push('a');
Structs with Lifetime Parameters
struct Extrema<'elt> {
greatest: &'elt i32,
least: &'elt i32,
}
fn find_extrema<'s>(slice: &'s [i32]) -> Extrema<'s> {
let mut greatest = &slice[0];
let mut least = &slice[0];
for i in 1..slice.len() {
if slice[i] < *least { least = &slice[i]; }
if slice[i] > *greatest { greatest = &slice[i]; }
}
Extrema { greatest, least }
}
Deriving Common Traits for Struct Types
#[derive(Copy, Clone, Debug, PartialEq)]
struct Point {
x: f64,
y: f64
}
{
use std::cell::RefCell;
let ref_cell: RefCell<String> = RefCell::new("hello".to_string());
let r = ref_cell.borrow();
let count = r.len();
assert_eq!(count,5);
let mut w = ref_cell.borrow_mut();
w.push_str("world");
}
thread '<unnamed>' panicked at src/lib.rs:247:22:
already borrowed: BorrowMutError
stack backtrace:
0: rust_begin_unwind
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/std/src/panicking.rs:597:5
1: core::panicking::panic_fmt
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/panicking.rs:72:14
2: core::cell::panic_already_borrowed
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/cell.rs:762:5
3: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
4: run_user_code_39
5: evcxr::runtime::Runtime::run_loop
6: evcxr::runtime::runtime_hook
7: evcxr_jupyter::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Enums and Patterns
use std::cmp::Ordering;
fn compare(a: i32,b: i32) -> Ordering {
if a > b {
Ordering::Greater
} else if a < b {
Ordering::Less
} else {
Ordering::Equal
}
}
enum HttpStatus {
Ok = 200,
NotModified = 304,
NotFound = 404,
}
use std::mem::size_of;
assert_eq!(size_of::<Ordering>(), 1);
assert_eq!(size_of::<HttpStatus>(), 2); // 404 doesn't fit in a u8
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum TimeUnit {
Seconds, Minutes, Hours, Days, Months, Years,
}
impl TimeUnit {
/// Return the plural noun for this time unit.
fn plural(self) -> &'static str {
match self {
TimeUnit::Seconds => "seconds",
TimeUnit::Minutes => "minutes",
TimeUnit::Hours => "hours",
TimeUnit::Days => "days",
TimeUnit::Months => "months",
TimeUnit::Years => "years",
}
}
/// Return the singular noun for this time unit.
fn singular(self) -> &'static str {
self.plural().trim_end_matches('s')
}
}
Enums in Memory
Patterns
enum RoughTime {
InThePast(TimeUnit, u32),
JustNow,
InTheFuture(TimeUnit, u32),
}
fn rough_time_to_english(rt: RoughTime) -> String {
match rt {
RoughTime::InThePast(units, count) =>
format!("{} {} ago", count, units.plural()),
RoughTime::JustNow =>
format!("just now"),
RoughTime::InTheFuture(units, count) =>
format!("{} {} from now", count, units.plural()),
}
}
fn greet_people(names: &[&str]) {
match names {
[] => { println!("Hello, nobody.") },
[a] => { println!("Hello, {}.", a) },
[a, b] => { println!("Hello, {} and {}.", a, b) },
[a, .., b] => { println!("Hello, everyone from {} to {}.", a, b) }
}
}
// An ordered collection of `T`s.
enum BinaryTree<T> {
Empty,
NonEmpty(Box<TreeNode<T>>),
}
// A part of a BinaryTree.
struct TreeNode<T> {
element: T,
left: BinaryTree<T>,
right: BinaryTree<T>,
}
impl <T: Ord> BinaryTree<T> {
fn add(&mut self,value :T) {
match *self {
BinaryTree::Empty => {
*self = BinaryTree::NonEmpty(Box::new(
TreeNode {
element: value,
left: BinaryTree::Empty,
right: BinaryTree::Empty,
}
))
},
BinaryTree::NonEmpty(ref mut node) => {
if value <= node.element {
node.left.add(value);
} else {
node.right.add(value);
}
}
}
}
}