Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

oversized-impl

Level: warn · Article: Structs

A struct with 25 methods is usually three structs that haven’t been separated yet.

What it checks

The inherent impls of one type, in one file, hold more than 20 methods.

Don’t

#![allow(unused)]
fn main() {
struct User {
    events: Vec<UserEvent>,
}

impl User {
    fn activate(&mut self) {
        self.events.push(UserEvent::Activate);
    }

    fn archive(&mut self) {
        self.events.push(UserEvent::Archive);
    }

    fn ban(&mut self) {
        self.events.push(UserEvent::Ban);
    }

    fn charge(&mut self, amount: Money) {
        self.events.push(UserEvent::Charge(amount));
    }

    fn deactivate(&mut self) {
        self.events.push(UserEvent::Deactivate);
    }

    fn delete(&mut self) {
        self.events.push(UserEvent::Delete);
    }

    fn export(&mut self) {
        self.events.push(UserEvent::Export);
    }

    fn invite(&mut self) {
        self.events.push(UserEvent::Invite);
    }

    fn invoice(&mut self, amount: Money) {
        self.events.push(UserEvent::Invoice(amount));
    }

    fn lock(&mut self) {
        self.events.push(UserEvent::Lock);
    }

    fn notify(&mut self, message: Message) {
        self.events.push(UserEvent::Notified(message));
    }

    fn promote(&mut self) {
        self.events.push(UserEvent::Promote);
    }

    fn refund(&mut self, amount: Money) {
        self.events.push(UserEvent::Refund(amount));
    }

    fn rename(&mut self, name: UserName) {
        self.events.push(UserEvent::Renamed(name));
    }

    fn restore(&mut self) {
        self.events.push(UserEvent::Restore);
    }

    fn subscribe(&mut self) {
        self.events.push(UserEvent::Subscribe);
    }

    fn suspend(&mut self) {
        self.events.push(UserEvent::Suspend);
    }

    fn unban(&mut self) {
        self.events.push(UserEvent::Unban);
    }

    fn unlock(&mut self) {
        self.events.push(UserEvent::Unlock);
    }

    fn unsubscribe(&mut self) {
        self.events.push(UserEvent::Unsubscribe);
    }

    fn upgrade(&mut self) {
        self.events.push(UserEvent::Upgrade);
    }
}
}

Do

#![allow(unused)]
fn main() {
struct User {
    billing: BillingProfile,
    events: Vec<UserEvent>,
    notifications: NotificationSettings,
}

impl User {
    fn ban(&mut self) {
        self.events.push(UserEvent::Banned);
    }

    fn promote(&mut self) {
        self.events.push(UserEvent::Promoted);
    }
}

struct BillingProfile {
    ledger: Vec<Charge>,
}

impl BillingProfile {
    fn charge(&mut self, amount: Money) {
        self.ledger.push(Charge::Debit(amount));
    }

    fn invoice(&self) -> Invoice {
        Invoice::from_ledger(&self.ledger)
    }

    fn refund(&mut self, amount: Money) {
        self.ledger.push(Charge::Credit(amount));
    }
}

struct NotificationSettings {
    channels: Vec<Channel>,
}

impl NotificationSettings {
    fn notify(&self, message: Message) {
        for channel in &self.channels {
            channel.send(&message);
        }
    }

    fn subscribe(&mut self, channel: Channel) {
        self.channels.push(channel);
    }

    fn unsubscribe(&mut self, channel: &Channel) {
        self.channels.retain(|existing| existing != channel);
    }
}
}

Ask which methods operate on a subset of the fields. That subset is its own struct, with five methods that actually belong to it.

Options

[thresholds]
oversized-impl = 20

Silence it

#![allow(unused)]
fn main() {
// rabot: allow(oversized-impl) builder: one method per option is the whole point
impl CommandBuilder { .. }
}