-
-
Save tomoima525/1397a359da847390a685fd43cca28a4b to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
This file contains hidden or 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
// Implementing Vector | |
pub struct ToyVec<T> { | |
elements: Box<[T]>, | |
len: usize, | |
} | |
// Reference type field requires lifetime specifier | |
pub struct Iter<'vec, T> { | |
elements: &'vec Box<[T]>, | |
len: usize, | |
pos: usize | |
} | |
// Set Trait boundary of Default to get the default value of T | |
impl<T: Default> ToyVec<T> { | |
pub fn new() -> Self { | |
Self::with_capacity(0) | |
} | |
pub fn with_capacity(capacity: usize) -> Self { | |
Self { | |
elements: Self::allocate_in_heap(capacity), | |
len: 0 | |
} | |
} | |
pub fn len(&self) -> usize { | |
self.len | |
} | |
pub fn capacity(&self) -> usize { | |
self.elements.len() | |
} | |
// Passing mutable reference of self, so we are manipulating ToyVec | |
// Passing T type, meaning the ownership of element will move to this function then to ToyVec | |
pub fn push(&mut self, element: T) { | |
if self.len == self.capacity() { | |
self.grow(); | |
} | |
self.elements[self.len] = element; | |
self.len += 1; | |
} | |
// Passing reference without mutable, so we are not manipulating ToyVec | |
// Function returns immutable reference which self owns or none | |
pub fn get(&self, index: usize) -> Option<&T> { | |
if index < self.len { | |
Some(&self.elements[index]) | |
} else { | |
None | |
} | |
} | |
// This will show a compile error about life cycle | |
// When arguments have &self, then returned value has the same life cycle with self | |
// However default_value can have longer or shorter lifecycle. | |
// pub fn get_or(&self, index: usize, default_value: &T) -> &T { | |
// match self.get(index) { | |
// Some(v) => v, | |
// None => default_value | |
// } | |
// } | |
// life time specifier 'a will define the lifecycle | |
// self and default_value are borrowed until the return type is alive | |
pub fn get_or<'a>(&'a self, index: usize, default_value: &'a T) -> &'a T { | |
self.get(index).unwrap_or(default_value) | |
} | |
// Returns value along with ownership | |
pub fn pop(&mut self) -> Option<T> { | |
if self.len == 0 { | |
None | |
} else { | |
// Below fails with "cannot move out of `self.elements[_]` which is behind a mutable reference" | |
// this method can not move the value to v because &mut does not allow moving ownership | |
// | |
// let v = self.elements[self.len - 1]; | |
// Instead we can replace with other value | |
let v = std::mem::replace(&mut self.elements[self.len], Default::default()); | |
self.len -= 1; | |
Some(v) | |
} | |
} | |
// ToyVec's ownership is borrowed while this iterator exists | |
pub fn iter<'vec>(&'vec self) -> Iter<'vec, T> { | |
Iter { | |
elements: &self.elements, | |
len: self.len, | |
pos: 0, | |
} | |
} | |
fn grow(&mut self) { | |
if self.capacity() == 0 { | |
self.elements = Self::allocate_in_heap(1) | |
} else { | |
let new_allocation = Self::allocate_in_heap(self.capacity() * 2); | |
let old_allocation = std::mem::replace(&mut self.elements, new_allocation); | |
// move existing values to the new allocation | |
for (i, element) in old_allocation.into_vec().into_iter().enumerate() { | |
self.elements[i] = element; | |
} | |
} | |
} | |
fn allocate_in_heap(capacity: usize) -> Box<[T]> { | |
std::iter::repeat_with(Default::default) | |
.take(capacity) | |
.collect::<Vec<_>>() | |
.into_boxed_slice() | |
} | |
} | |
impl<'vec, T> Iterator for Iter<'vec, T> { | |
type Item = &'vec T; | |
fn next(&mut self) -> Option<Self::Item> { | |
if self.pos >= self.len { | |
None | |
} else { | |
let res = Some(&self.elements[self.pos]); | |
self.pos += 1; | |
res | |
} | |
} | |
} | |
fn main() { | |
let mut v = ToyVec::new(); | |
v.push("ABC".to_string()); | |
v.push("DEF".to_string()); | |
let mut iter = v.iter(); | |
// this will fail since v is borrowed as immutable | |
// cannot borrow `v` as mutable because it is also borrowed as immutable | |
// v.push("HIJ".to_string()); | |
// Return value drops inside assert_eq, so ownership is returned to v | |
assert_eq!(iter.next(), Some(&"ABC".to_string())); | |
// borrow value from v | |
let e0 = v.get(1); | |
assert_eq!(e0, Some(&"DEF".to_string())); | |
let default_value = &"OTHER".to_string(); | |
let e1 = v.get_or(10, default_value); | |
assert_eq!(e1, &"OTHER".to_string()); | |
let e2 = v.pop(); | |
assert_eq!(e2.unwrap(), "DEF".to_string()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment