简介
borrow trait
是处理借用(即其它语言中的引用)的 trait,变量的所有权不会转移.泛型定义如下:
pub trait Borrow<Borrowed: ?Sized> {/// Immutably borrows from an owned value.fn borrow(&self) -> &Borrowed;
}
其中包含一个 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}
}
这里创建一个自定义类型来说明 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();}
自定义 borrow trait
String
类型就实现了自己的 borrow trait
,如下:
impl Borrow<str> for String {#[inline]fn borrow(&self) -> &str {&self[..]}
}
即将 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()}
}
实现Borrow
的一个要求是,借用值的Hash
、Eq
和Ord
与拥有值的Hash
、Eq
和Ord
相等。这里可以解释为,如果两个用户 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);}
例如,上面的函数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);}
这样只要确保类型 s
,都实现了 borrow()
方法,且返回值的类型都为 &str
就可行了.
再修改成第二个版本, 这样就可以将任何实现了Borrow<str>
类型的变量作为参数传递给函数check
,如下:
fn check<K>(s: K)whereK: Borrow<str>,{let borrowed: &str = s.borrow();assert_eq!("Hello", borrowed);}#[test]fn test_borrow_as_param() {// 支持 String 类型,因为 String 实现了 Borrow trait,可以转换为 &strlet 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);}