לדלג לתוכן

2.4 - גודל טיפוסים וחישוב בזמן קומפילציה - פתרון

פתרון הפרדה בין קיבולת לאורך

האינווריאנט הוא שהאורך אינו עולה על N. הפעולה היחידה שמגדילה אותו בודקת את הגבול לפני הכתיבה, ולכן as_slice יכולה להחזיר טווח חוקי.

struct Buffer<const N: usize> {
    bytes: [u8; N],
    len: usize,
}

impl<const N: usize> Buffer<N> {
    fn new() -> Self { Self { bytes: [0; N], len: 0 } }
    fn push(&mut self, byte: u8) -> bool {
        if self.len == N { return false; }
        self.bytes[self.len] = byte;
        self.len += 1;
        true
    }
    fn as_slice(&self) -> &[u8] { &self.bytes[..self.len] }
}

fn main() {
    let mut empty = Buffer::<0>::new();
    assert!(!empty.push(1));
    let mut buffer = Buffer::<2>::new();
    assert!(buffer.push(10));
    assert!(buffer.push(20));
    assert!(!buffer.push(30));
    assert_eq!(buffer.as_slice(), &[10, 20]);
}

הקיבולת קבועה לכל מופע מן הטיפוס המסוים, ואילו האורך משתנה כאשר מוסיפים נתונים. כל האיברים כבר מאותחלים, גם אלה שאינם פעילים, ולכן הפתרון פשוט אך עשוי לבצע אתחול שאינו נחוץ במבנה כללי. בפרק unsafe נבדוק כיצד לחסוך אותו בלי לאבד תקינות.