• rust - 理解borrow trait


    简介

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

    pub trait Borrow<Borrowed: ?Sized> {
        /// Immutably borrows from an owned value.
        fn borrow(&self) -> &Borrowed;
    }
    
    • 1
    • 2
    • 3
    • 4

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

    默认实现

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

    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
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

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

        #[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();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    自定义 borrow trait

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

    impl Borrow<str> for String {
        #[inline]
        fn borrow(&self) -> &str {
            &self[..]
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

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

    #[allow(dead_code)]
    struct Person {
        name: String,
        age: u8,
    }
    
    impl Borrow<str> for Person {
        fn borrow(&self) -> &str {
            self.name.as_str()
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

    使用场景

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

        #[test]
        fn test_origin_check() {
            fn origin_check(s: &String) {
                assert_eq!("Hello", s);
            }
    
            let s = "Hello".to_string();
            origin_check(&s);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

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

        #[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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

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

        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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    【图论】负环
    PHP: GetCattle算法(N年后有多少头牛)(附完整源码)
    三大赛题指南发布!2023 冬季波卡黑客松本周末开启 Workshop
    小程序源码:最新牛牛盲盒微信小程序源码下载·一元购升级款,全新流量变现程序,带图片完整素材
    牛客剑指offer刷题算法篇
    react学习笔记1
    外包干了2个月,技术退步明显.......
    Vue-ref属性(脚手架获取DOM元素)、props配置、mixin混入、插件、scoped样式
    FFmpeg 命令:从入门到精通 | ffmpeg 命令提取像素格式和 PCM 数据
    vue的路由
  • 原文地址:https://blog.csdn.net/liuyuan_jq/article/details/134022877