A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://rust-lang.github.io/api-guidelines/flexibility.html below:

Flexibility - Rust API Guidelines

Flexibility Functions expose intermediate results to avoid duplicate work (C-INTERMEDIATE)

Many functions that answer a question also compute interesting related data. If this data is potentially of interest to the client, consider exposing it in the API.

Examples from the standard library Caller decides where to copy and place data (C-CALLER-CONTROL)

If a function requires ownership of an argument, it should take ownership of the argument rather than borrowing and cloning the argument.


#![allow(unused)]
fn main() {
// Prefer this:
fn foo(b: Bar) {
    /* use b as owned, directly */
}

// Over this:
fn foo(b: &Bar) {
    let b = b.clone();
    /* use b as owned after cloning */
}
}

If a function does not require ownership of an argument, it should take a shared or exclusive borrow of the argument rather than taking ownership and dropping the argument.


#![allow(unused)]
fn main() {
// Prefer this:
fn foo(b: &Bar) {
    /* use b as borrowed */
}

// Over this:
fn foo(b: Bar) {
    /* use b as borrowed, it is implicitly dropped before function returns */
}
}

The Copy trait should only be used as a bound when absolutely needed, not as a way of signaling that copies should be cheap to make.

Functions minimize assumptions about parameters by using generics (C-GENERIC)

The fewer assumptions a function makes about its inputs, the more widely usable it becomes.

Prefer


#![allow(unused)]
fn main() {
fn foo<I: IntoIterator<Item = i64>>(iter: I) { /* ... */ }
}

over any of


#![allow(unused)]
fn main() {
fn foo(c: &[i64]) { /* ... */ }
fn foo(c: &Vec<i64>) { /* ... */ }
fn foo(c: &SomeOtherCollection<i64>) { /* ... */ }
}

if the function only needs to iterate over the data.

More generally, consider using generics to pinpoint the assumptions a function needs to make about its arguments.

Advantages of generics Disadvantages of generics Examples from the standard library Traits are object-safe if they may be useful as a trait object (C-OBJECT)

Trait objects have some significant limitations: methods invoked through a trait object cannot use generics, and cannot use Self except in receiver position.

When designing a trait, decide early on whether the trait will be used as an object or as a bound on generics.

If a trait is meant to be used as an object, its methods should take and return trait objects rather than use generics.

A where clause of Self: Sized may be used to exclude specific methods from the trait's object. The following trait is not object-safe due to the generic method.


#![allow(unused)]
fn main() {
trait MyTrait {
    fn object_safe(&self, i: i32);

    fn not_object_safe<T>(&self, t: T);
}
}

Adding a requirement of Self: Sized to the generic method excludes it from the trait object and makes the trait object-safe.


#![allow(unused)]
fn main() {
trait MyTrait {
    fn object_safe(&self, i: i32);

    fn not_object_safe<T>(&self, t: T) where Self: Sized;
}
}
Advantages of trait objects Disadvantages of trait objects Examples from the standard library

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4