rust - 理解borrow trait

简介

borrow trait 是处理借用(即其它语言中的引用)的 trait,变量的所有权不会转移.泛型定义如下:

rust 复制代码
pub trait Borrow<Borrowed: ?Sized> {
    /// Immutably borrows from an owned value.
    fn borrow(&self) -> &Borrowed;
}

其中包含一个 borrow(&self)的方法,将变量的类型 T 转换为 &Borrowed 类型.

默认实现

rust 提供了类型 T 的默认实现,如下:

rust 复制代码
impl<T: ?Sized> Borrow<T> for T {
    fn borrow(&self) -> &T {
        self
    }
}

impl<T: ?Sized> Borrow<T> for &T {
    fn borrow(&self) -> &T {
        &**self
    }
}

impl<T: ?Sized> Borrow<T> for &mut T {
    fn borrow(&self) -> &T {
        &**self
    }
}

这里创建一个自定义类型来说明 borrow 的默认实现,如下

rust 复制代码
    #[test]
    fn test_default_borrow() {
        struct MyType;

        let my_type = MyType;
        let _: &MyType = my_type.borrow();
        let _: &MyType = (&my_type).borrow();

        let my_type = &MyType;
        let _: &MyType = my_type.borrow();
        let _: &MyType = (*my_type).borrow();

        let my_type = &mut MyType;
        let _: &MyType = my_type.borrow();
        let _: &MyType = (*my_type).borrow();
    }

自定义 borrow trait

String 类型就实现了自己的 borrow trait,如下:

rust 复制代码
impl Borrow<str> for String {
    #[inline]
    fn borrow(&self) -> &str {
        &self[..]
    }
}

即将 String 类型转换为了 &str 类型.

可以自己对类型实现 Borrow trait,如下:

rust 复制代码
#[allow(dead_code)]
struct Person {
    name: String,
    age: u8,
}

impl Borrow<str> for Person {
    fn borrow(&self) -> &str {
        self.name.as_str()
    }
}

实现Borrow的一个要求是,借用值的HashEqOrd与拥有值的HashEqOrd相等。这里可以解释为,如果两个用户 Person 的借用值 name 相同,则认为是同一个人.

使用场景

1. 对函数参数进行类型扩展

rust 复制代码
    #[test]
    fn test_origin_check() {
        fn origin_check(s: &String) {
            assert_eq!("Hello", s);
        }

        let s = "Hello".to_string();
        origin_check(&s);
    }

例如,上面的函数origin_check接受 String 类型的参数,但是如果想复用这个函数,需要将其它类型的参数也传给origin_check函数该怎么实现呢?

先修改成第一个版本, 添加s.borrow(), 如下

rust 复制代码
    #[test]
    fn test_origin_check_1() {
        fn origin_check(s: &String) {
            let borrowed: &str = s.borrow();
            assert_eq!("Hello", borrowed);
        }

        let s = "Hello".to_string();
        origin_check(&s);
    }

这样只要确保类型 s,都实现了 borrow()方法,且返回值的类型都为 &str就可行了.

再修改成第二个版本, 这样就可以将任何实现了Borrow<str>类型的变量作为参数传递给函数check,如下:

rust 复制代码
    fn check<K>(s: K)
    where
        K: Borrow<str>,
    {
        let borrowed: &str = s.borrow();
        assert_eq!("Hello", borrowed);
    }

    #[test]
    fn test_borrow_as_param() {
        // 支持 String 类型,因为 String 实现了 Borrow trait,可以转换为 &str
        let s = "Hello".to_string();
        check(s);

        // 支持 &str 类型,因为 rust 实现了类型 T 的默认 borrow 实现, 转换为 &str 类型
        let s = "Hello";
        check(s);

        // 支持 Person 类型,因为 Person 实现了 Borrow trait, 可以转换为用户名属性的 &str 类型
        let s = Person { name: "Hello".to_string(), age: 18 };
        check(s);
    }
相关推荐
ithadoop7 小时前
Solana入门:区块链新手速成指南(第二阶段:开发入门)
rust·web3·区块链·智能合约·solana
Rust语言中文社区8 小时前
【Rust日报】2026-04-24 Vizia 0.4 发布——纯 Rust 声明式响应式 GUI 框架
开发语言·后端·rust
techdashen14 小时前
用自家产品构建自家产品:Cloudflare Images 的工程架构解析
开发语言·架构·rust
恋喵大鲤鱼15 小时前
RUST 的特色概念与 Go 到 Rust 的思维模式转变
rust
光影少年17 小时前
vite+rust生态链工具链
开发语言·前端·后端·rust·前端框架
techdashen18 小时前
服务不停,升级照常:Cloudflare 是怎么做到零中断重启的
开发语言·rust
Rust研习社18 小时前
Reqwest 兼顾简洁与高性能的现代 HTTP 客户端
开发语言·网络·后端·http·rust
Rust研习社1 天前
添加依赖库时的 features 是什么?优雅实现编译期条件编译与模块化开发
开发语言·后端·rust
Rust研习社1 天前
Rust 条件变量(Condvar)详解:线程同步的高效方式
后端·rust·编程语言