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);
    }
相关推荐
YiSLWLL6 小时前
Tauri2+Leptos开发桌面应用--绘制图形、制作GIF动画和mp4视频
python·rust·ffmpeg·音视频·matplotlib
uccs2 天前
使用 rust 创建多线程 http-server
后端·rust
pumpkin845143 天前
Rust 的核心工具链
rust
SomeB1oody3 天前
【Rust自学】13.8. 迭代器 Pt.4:创建自定义迭代器
开发语言·后端·rust
半夏知半秋3 天前
rust学习-函数的定义与使用
服务器·开发语言·后端·学习·rust
SomeB1oody4 天前
【Rust自学】13.6. 迭代器 Pt.2:消耗和产生迭代器的方法
开发语言·后端·rust
Hello.Reader4 天前
Rust 数据类型详解
开发语言·后端·rust
gs801405 天前
2025年编程语言热度分析:Python领跑,Go与Rust崛起
python·golang·rust
老猿讲编程5 天前
详解Rust 中 String 和 str 的用途与区别
开发语言·后端·rust
rongjv5 天前
[rustGUI][iced]基于rust的GUI库iced(0.13)的部件学习(05):svg图片转为png格式(暨svg部件的使用)
rust·gui·iced