Course contentsShow
← Rust
Lesson 567 of 1,9105. Type System and TraitsFree lesson

The Borrow Trait Pattern

Improve API versatility by accepting owned or borrowed versions of the same data.

In this lesson, you will learn how to make your functions more flexible by allowing them to accept either owned data or a reference to that data using the Borrow trait.

The Problem: API Rigidity

Imagine you have a function that processes a String. If you define it as fn process(s: &String), you force the caller to provide a reference. If they have an owned String, they must manually borrow it. If you define it as fn process(s: String), you force the caller to give up ownership. Often, you want an API that is "polymorphic" enough to accept both, without making the caller perform gymnastics.

The Solution: Using std::borrow::Borrow

The Borrow trait allows you to treat different types as if they were the same borrowed type. It is commonly used in function signatures to let the caller pass in an owned type (like String) or a slice (like &str) interchangeably.

Here is how you implement it:

use std::borrow::Borrow;

fn print_data<T>(input: T) 
where 
    T: Borrow<str> 
{
    println!("Data: {}", input.borrow());
}

fn main() {
    let owned = String::from("Hello");
    let borrowed = "World";

    print_data(owned);    // Works with owned String
    print_data(borrowed); // Works with &str
}

How It Works

The Borrow trait defines a borrow() method that returns a reference to the underlying data. By specifying T: Borrow<str> in our generic bounds, we tell Rust: "I don't care if the caller provides an owned String or a static &str; as long as both can be represented as a &str, this function will work."

This pattern is cleaner than using AsRef, as Borrow carries the semantic intent that the type provided is "equivalent" to the type you are borrowing, including requirements for consistent hashing and equality (which is important if you use these types as keys in a HashMap). It effectively hides the difference between ownership states, making your APIs feel much more ergonomic for the end user.

Key Takeaway: Use the Borrow trait to create flexible APIs that accept either owned or borrowed versions of the same data, allowing your functions to handle diverse input types seamlessly.